From 227a31b7883199c640decd64bd4692c4c48d57d4 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 28 Mar 2017 13:54:54 -0400 Subject: [PATCH] out_row_aligned_max_width() This PR improves `out_row_aligned_max_width()` in a few ways: * It makes better use of bash's string manipulation capabilities in order to simplify the function. * It improves the function's performance. One of the most costly parts of `out_row_aligned_max_width()` was the while loop to print each entry in the text. Since there is only one place in the code where the the entries are not all printed the same ways (the list of supported curves printed by `run_pfs()`), the PR changes `out_row_aligned_max_width()` to just return a plain text string, which the calling function prints in the appropriate way. For the curves printed by `run_pfs()`, a new function, `out_row_aligned_max_width_by_entry()` takes care of getting the output from `out_row_aligned_max_width()` and then printing each entry appropriately. * The PR also introduces a trick so that when the TLS extensions are printed, the text for an extension won't get split across two rows. It does this by replacing the space charters within the text for an extension with "}", formatting the result with `out_row_aligned_max_width()`, and then converting the "}" back to space characters. --- testssl.sh | 118 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 50 deletions(-) diff --git a/testssl.sh b/testssl.sh index 885e5e1..3272d4c 100755 --- a/testssl.sh +++ b/testssl.sh @@ -1222,63 +1222,73 @@ out_row_aligned() { } # prints text over multiple lines, trying to make no line longer than $max_width. -# Each line is indented with $spaces and each word in $text is printed using $print_function. +# Each line is indented with $spaces. out_row_aligned_max_width() { local text="$1" local spaces="$2" local -i max_width="$3" - local print_function="$4" local -i i len local cr=$'\n' - local line entry first=true last=false + local line first=true - max_width=$max_width-1 # at the moment we align to terminal width. This makes sure we don't wrap too late max_width=$max_width-${#spaces} len=${#text} while true; do - i=$max_width - if [[ $i -ge $len ]]; then + if [[ $len -lt $max_width ]]; then + # If the remaining text to print is shorter than $max_width, + # then just print it. i=$len else - while true; do - [[ "${text:i:1}" == " " ]] && break - [[ $i -eq 0 ]] && break - i=$i-1 - done - if [[ $i -eq 0 ]]; then - i=$max_width+1 - while true; do - [[ "${text:i:1}" == " " ]] && break - [[ $i -eq $len ]] && break - i+=1 - done + # Find the final space character in the text that is less than + # $max_width characters into the remaining text, and make the + # text up to that space character the next line to print. + line="${text:0:max_width}" + line="${line% *}" + i=${#line} + if [[ $i -eq $max_width ]]; then + # If there are no space characters in the first $max_width + # characters of the remaining text, then make the text up + # to the first space the next line to print. If there are + # no space characters in the remaining text, make the + # remaining text the next line to print. + line="${text#* }" + i=$len-${#line} + [[ $i -eq 0 ]] && i=$len fi fi - if [[ $i -eq $len ]]; then - line="$text" - if ! "$first"; then - out "${cr}${spaces}" - fi - last=true - else - line="${text:0:i}" - if ! "$first"; then - out "${cr}${spaces}" - fi - len=$len-$i-1 - i=$i+1 - text="${text:i:len}" - first=false - [[ $len -eq 0 ]] && last=true + if ! "$first"; then + tm_out "${cr}${spaces}" fi - while read entry; do - $print_function "$entry" ; out " " - done <<< "$(tr ' ' '\n' <<< "$line")" - "$last" && break + tm_out "${text:0:i}" + [[ $i -eq $len ]] && break + len=$len-$i-1 + i=$i+1 + text="${text:i:len}" + first=false + [[ $len -eq 0 ]] && break done return 0 } +out_row_aligned_max_width_by_entry() { + local text="$1" + local spaces="$2" + local -i max_width="$3" + local print_function="$4" + local resp entry prev_entry=" " + + resp="$(out_row_aligned_max_width "$text" "$spaces" "$max_width")" + while read -d " " entry; do + if [[ -n "$entry" ]]; then + $print_function "$entry" + elif [[ -n "$prev_entry" ]]; then + outln; out " " + fi + out " " + prev_entry="$entry" + done <<< "$resp" +} + tmpfile_handle() { mv $TMPFILE "$TEMPDIR/$NODEIP.$1" 2>/dev/null @@ -4877,7 +4887,7 @@ cipher_pref_check() { if [[ -n "$order" ]]; then outln out "$(printf " %-10s " "$proto: ")" - out_row_aligned_max_width "$order" " " $TERM_WIDTH out + out "$(out_row_aligned_max_width "$order" " " $TERM_WIDTH)" fileout "order_$p" "INFO" "Default cipher order for protocol $p: $order" fi done @@ -5773,7 +5783,7 @@ certificate_info() { while read san; do [[ -n "$san" ]] && all_san+="$san " done <<< "$sans" - out_row_aligned_max_width "$all_san" "$indent " $TERM_WIDTH pr_italic + pr_italic "$(out_row_aligned_max_width "$all_san" "$indent " $TERM_WIDTH)" fileout "${json_prefix}san" "INFO" "subjectAltName (SAN) : $all_san" else out "-- " @@ -6078,7 +6088,7 @@ run_server_defaults() { local -a previous_hostcert previous_intermediates keysize cipher local -a ocsp_response ocsp_response_status sni_used local -a ciphers_to_test success - local cn_nosni cn_sni sans_nosni sans_sni san + local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions local alpn_proto alpn="" alpn_list_len_hex alpn_extn_len_hex success local -i alpn_list_len alpn_extn_len @@ -6216,7 +6226,16 @@ run_server_defaults() { fileout "tls_extensions" "INFO" "TLS server extensions (std): (none)" else #FIXME: we rather want to have the chance to print each ext in italcs or another format. Atm is a string of quoted strings -- that needs to be fixed at the root - out_row_aligned_max_width "$TLS_EXTENSIONS" " " $TERM_WIDTH out; outln + # out_row_aligned_max_width() places line breaks at space characters. + # So, in order to prevent the text for an extension from being broken + # across lines, temporarily replace space characters within the text + # of an extension with "}", and then convert the "}" back to space in + # the output of out_row_aligned_max_width(). + tls_extensions="${TLS_EXTENSIONS// /{}" + tls_extensions="${tls_extensions//\"{\"/\" \"}" + tls_extensions="$(out_row_aligned_max_width "$tls_extensions" " " $TERM_WIDTH)" + tls_extensions="${tls_extensions//{/ }" + outln "$tls_extensions" fileout "tls_extensions" "INFO" "TLS server extensions (std): $TLS_EXTENSIONS" fi @@ -6443,7 +6462,7 @@ run_pfs() { outln "${sigalg[i]}" fi done - ! "$WIDE" && out_row_aligned_max_width "$pfs_ciphers" " " $TERM_WIDTH out + ! "$WIDE" && out "$(out_row_aligned_max_width "$pfs_ciphers" " " $TERM_WIDTH)" debugme echo $pfs_offered "$WIDE" || outln fileout "pfs_ciphers" "INFO" "(Perfect) Forward Secrecy Ciphers: $pfs_ciphers" @@ -6524,7 +6543,7 @@ run_pfs() { if [[ -n "$curves_offered" ]]; then "$WIDE" && outln pr_bold " Elliptic curves offered: " - out_row_aligned_max_width "$curves_offered" " " $TERM_WIDTH pr_ecdh_curve_quality + out_row_aligned_max_width_by_entry "$curves_offered" " " $TERM_WIDTH pr_ecdh_curve_quality outln fileout "ecdhe_curves" "INFO" "Elliptic curves offered $curves_offered" fi @@ -10079,8 +10098,8 @@ run_beast(){ ! "$first" && out "$spaces" out "$(toupper $proto): " [[ -n "$higher_proto_supported" ]] && \ - out_row_aligned_max_width "$detected_cbc_ciphers" " " $TERM_WIDTH pr_svrty_low || \ - out_row_aligned_max_width "$detected_cbc_ciphers" " " $TERM_WIDTH pr_svrty_medium + pr_svrty_low "$(out_row_aligned_max_width "$detected_cbc_ciphers" " " $TERM_WIDTH)" || \ + pr_svrty_medium "$(out_row_aligned_max_width "$detected_cbc_ciphers" " " $TERM_WIDTH)" outln detected_cbc_ciphers="" # empty for next round first=false @@ -10417,7 +10436,7 @@ run_rc4() { fi fi done - ! "$WIDE" && out_row_aligned_max_width "$rc4_detected" " " $TERM_WIDTH pr_svrty_high + ! "$WIDE" && pr_svrty_high "$(out_row_aligned_max_width "$rc4_detected" " " $TERM_WIDTH)" outln "$WIDE" && pr_svrty_high "VULNERABLE (NOT ok)" fileout "rc4" "HIGH" "RC4: VULNERABLE, Detected ciphers: $rc4_detected" "$cve" "$cwe" "$hint" @@ -11665,8 +11684,7 @@ display_rdns_etc() { further_ip_addrs+="$ip " fi done - out_row_aligned_max_width "$further_ip_addrs" " $CORRECT_SPACES" $TERM_WIDTH out - outln + outln "$(out_row_aligned_max_width "$further_ip_addrs" " $CORRECT_SPACES" $TERM_WIDTH)" fi if "$LOCAL_A"; then outln " A record via $CORRECT_SPACES /etc/hosts " @@ -11675,7 +11693,7 @@ display_rdns_etc() { fi if [[ -n "$rDNS" ]]; then out "$(printf " %-23s %s" "rDNS ($nodeip):")" - out_row_aligned_max_width "$rDNS" " $CORRECT_SPACES" $TERM_WIDTH out + out "$(out_row_aligned_max_width "$rDNS" " $CORRECT_SPACES" $TERM_WIDTH)" fi }