diff --git a/testssl.sh b/testssl.sh index 37b1ea3..be106a8 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3521,6 +3521,7 @@ run_client_simulation() { local i=0 local name tls proto cipher temp what_dh bits curve local has_dh_bits using_sockets=true + local client_service # source the external file . "$TESTSSL_INSTALL_DIR/etc/client_simulation.txt" 2>/dev/null @@ -3529,14 +3530,18 @@ run_client_simulation() { return 1 fi - #FIXME, see client_simulation branch which has to be merged - if "$SSL_NATIVE" || [[ -n "$STARTTLS" ]]; then - using_sockets=false - fi + "$SSL_NATIVE" && using_sockets=false - # doesn't make sense for other services - if [[ $SERVICE != "HTTP" ]]; then - return 0 + if [[ $SERVICE != "" ]]; then + client_service="$SERVICE" + else + # Can we take the service from STARTTLS? + if [[ -n "$STARTTLS_PROTOCOL" ]]; then + client_service=$(toupper "${STARTTLS_PROTOCOL%s}") # strip trailing 's' in ftp(s), smtp(s), pop3(s), etc + else + outln "Could not determine which protocol was started, only simulating generic clients." + client_service="undetermined" + fi fi outln @@ -3550,7 +3555,7 @@ run_client_simulation() { outln debugme tmln_out - + if "$WIDE"; then if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then out " Browser Protocol Cipher Suite Name (OpenSSL) " @@ -3567,116 +3572,121 @@ run_client_simulation() { outln fi for name in "${short[@]}"; do - out " $(printf -- "%-33s" "${names[i]}")" - if "$using_sockets" && [[ -n "${handshakebytes[i]}" ]]; then - client_simulation_sockets "${handshakebytes[i]}" - sclient_success=$? - if [[ $sclient_success -eq 0 ]]; then - if [[ "0x${DETECTED_TLS_VERSION}" -lt ${lowest_protocol[i]} ]] || \ - [[ "0x${DETECTED_TLS_VERSION}" -gt ${highest_protocol[i]} ]]; then - sclient_success=1 - fi - [[ $sclient_success -eq 0 ]] && cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE >$ERRFILE - fi - else - ! "$HAS_NO_SSL2" && protos[i]="$(sed 's/-no_ssl2//' <<< "${protos[i]}")" - debugme echo "$OPENSSL s_client -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE - sclient_connect_successful $? $TMPFILE - sclient_success=$? - fi - if [[ $sclient_success -eq 0 ]]; then - # If an ephemeral DH key was used, check that the number of bits is within range. - temp=$(awk -F': ' '/^Server Temp Key/ { print $2 }' "$TMPFILE") # extract line - what_dh=$(awk -F',' '{ print $1 }' <<< $temp) - bits=$(awk -F',' '{ print $3 }' <<< $temp) - if grep -q bits <<< $bits; then - curve="$(strip_spaces "$(awk -F',' '{ print $2 }' <<< $temp)")" - else - curve="" - bits=$(awk -F',' '{ print $2 }' <<< $temp) - fi - bits="${bits/bits/}" - bits="${bits// /}" - if [[ "$what_dh" == "X25519" ]] || [[ "$what_dh" == "X448" ]]; then - curve="$what_dh" - what_dh="ECDH" - fi - if [[ "$what_dh" == "DH" ]]; then - [[ ${minDhBits[i]} -ne -1 ]] && [[ $bits -lt ${minDhBits[i]} ]] && sclient_success=1 - [[ ${maxDhBits[i]} -ne -1 ]] && [[ $bits -gt ${maxDhBits[i]} ]] && sclient_success=1 - fi - fi - if [[ $sclient_success -ne 0 ]]; then - outln "No connection" - fileout "client_${short[i]}" "INFO" "$(strip_spaces "${names[i]}") client simulation: No connection" - else - proto=$(get_protocol $TMPFILE) - # hack: - [[ "$proto" == TLSv1 ]] && proto="TLSv1.0" - [[ "$proto" == SSLv3 ]] && proto="SSLv3 " - if [[ "$proto" == TLSv1.2 ]] && ( ! "$using_sockets" || [[ -z "${handshakebytes[i]}" ]] ); then - # OpenSSL reports TLS1.2 even if the connection is TLS1.1 or TLS1.0. Need to figure out which one it is... - for tls in ${tlsvers[i]}; do - debugme echo "$OPENSSL s_client $tls -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE - sclient_connect_successful $? $TMPFILE + if ${current[i]} ; then + # for ANY we test this service or if the service we determined from STARTTLS matches + if [[ "${service[i]}" == "ANY" ]] || grep -q "$client_service" <<< "${service[i]}"; then + out " $(printf -- "%-33s" "${names[i]}")" + if "$using_sockets" && [[ -n "${handshakebytes[i]}" ]]; then + client_simulation_sockets "${handshakebytes[i]}" sclient_success=$? if [[ $sclient_success -eq 0 ]]; then - case "$tls" in - "-tls1_2") - break - ;; - "-tls1_1") - proto="TLSv1.1" - break - ;; - "-tls1") - proto="TLSv1.0" - break - ;; - esac + if [[ "0x${DETECTED_TLS_VERSION}" -lt ${lowest_protocol[i]} ]] || \ + [[ "0x${DETECTED_TLS_VERSION}" -gt ${highest_protocol[i]} ]]; then + sclient_success=1 + fi + [[ $sclient_success -eq 0 ]] && cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE >$ERRFILE fi - done - fi - cipher=$(get_cipher $TMPFILE) - if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]] && ( [[ "$cipher" == TLS_* ]] || [[ "$cipher" == SSL_* ]] ); then - cipher="$(rfc2openssl "$cipher")" - [[ -z "$cipher" ]] && cipher=$(get_cipher $TMPFILE) - elif [[ "$DISPLAY_CIPHERNAMES" =~ rfc ]] && [[ "$cipher" != TLS_* ]] && [[ "$cipher" != SSL_* ]]; then - cipher="$(openssl2rfc "$cipher")" - [[ -z "$cipher" ]] && cipher=$(get_cipher $TMPFILE) - fi - if ! "$WIDE"; then - out "$proto $cipher" - elif [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then - out "$(printf -- "%-7s %-33s" "$proto" "$cipher")" - else - out "$(printf -- "%-7s %-49s" "$proto" "$cipher")" - fi - if ! "$WIDE"; then - "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] && has_dh_bits=$HAS_DH_BITS && HAS_DH_BITS=true - "$HAS_DH_BITS" && read_dhbits_from_file $TMPFILE - "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] && HAS_DH_BITS=$has_dh_bits - elif [[ -n "$what_dh" ]]; then - [[ -n "$curve" ]] && curve="($curve)" - if [[ "$what_dh" == "ECDH" ]]; then - pr_ecdh_quality "$bits" "$(printf -- "%-12s" "$bits bit $what_dh") $curve" else - pr_dh_quality "$bits" "$(printf -- "%-12s" "$bits bit $what_dh") $curve" + ! "$HAS_NO_SSL2" && protos[i]="$(sed 's/-no_ssl2//' <<< "${protos[i]}")" + debugme echo "$OPENSSL s_client -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE + sclient_connect_successful $? $TMPFILE + sclient_success=$? fi - elif "$HAS_DH_BITS" || ( "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] ); then - out "No FS" - fi - outln - if [[ -n "${warning[i]}" ]]; then - out " " - outln "${warning[i]}" - fi - fileout "client_${short[i]}" "INFO" \ - "$(strip_spaces "${names[i]}") client simulation: $proto $cipher ${warning[i]}" - debugme cat $TMPFILE - fi + if [[ $sclient_success -eq 0 ]]; then + # If an ephemeral DH key was used, check that the number of bits is within range. + temp=$(awk -F': ' '/^Server Temp Key/ { print $2 }' "$TMPFILE") # extract line + what_dh=$(awk -F',' '{ print $1 }' <<< $temp) + bits=$(awk -F',' '{ print $3 }' <<< $temp) + if grep -q bits <<< $bits; then + curve="$(strip_spaces "$(awk -F',' '{ print $2 }' <<< $temp)")" + else + curve="" + bits=$(awk -F',' '{ print $2 }' <<< $temp) + fi + bits="${bits/bits/}" + bits="${bits// /}" + if [[ "$what_dh" == "X25519" ]] || [[ "$what_dh" == "X448" ]]; then + curve="$what_dh" + what_dh="ECDH" + fi + if [[ "$what_dh" == "DH" ]]; then + [[ ${minDhBits[i]} -ne -1 ]] && [[ $bits -lt ${minDhBits[i]} ]] && sclient_success=1 + [[ ${maxDhBits[i]} -ne -1 ]] && [[ $bits -gt ${maxDhBits[i]} ]] && sclient_success=1 + fi + fi + if [[ $sclient_success -ne 0 ]]; then + outln "No connection" + fileout "client_${short[i]}" "INFO" "$(strip_spaces "${names[i]}") client simulation: No connection" + else + proto=$(get_protocol $TMPFILE) + # hack: + [[ "$proto" == TLSv1 ]] && proto="TLSv1.0" + [[ "$proto" == SSLv3 ]] && proto="SSLv3 " + if [[ "$proto" == TLSv1.2 ]] && ( ! "$using_sockets" || [[ -z "${handshakebytes[i]}" ]] ); then + # OpenSSL reports TLS1.2 even if the connection is TLS1.1 or TLS1.0. Need to figure out which one it is... + for tls in ${tlsvers[i]}; do + debugme echo "$OPENSSL s_client $tls -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE + sclient_connect_successful $? $TMPFILE + sclient_success=$? + if [[ $sclient_success -eq 0 ]]; then + case "$tls" in + "-tls1_2") + break + ;; + "-tls1_1") + proto="TLSv1.1" + break + ;; + "-tls1") + proto="TLSv1.0" + break + ;; + esac + fi + done + fi + cipher=$(get_cipher $TMPFILE) + if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]] && ( [[ "$cipher" == TLS_* ]] || [[ "$cipher" == SSL_* ]] ); then + cipher="$(rfc2openssl "$cipher")" + [[ -z "$cipher" ]] && cipher=$(get_cipher $TMPFILE) + elif [[ "$DISPLAY_CIPHERNAMES" =~ rfc ]] && [[ "$cipher" != TLS_* ]] && [[ "$cipher" != SSL_* ]]; then + cipher="$(openssl2rfc "$cipher")" + [[ -z "$cipher" ]] && cipher=$(get_cipher $TMPFILE) + fi + if ! "$WIDE"; then + out "$proto $cipher" + elif [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then + out "$(printf -- "%-7s %-33s" "$proto" "$cipher")" + else + out "$(printf -- "%-7s %-49s" "$proto" "$cipher")" + fi + if ! "$WIDE"; then + "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] && has_dh_bits=$HAS_DH_BITS && HAS_DH_BITS=true + "$HAS_DH_BITS" && read_dhbits_from_file $TMPFILE + "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] && HAS_DH_BITS=$has_dh_bits + elif [[ -n "$what_dh" ]]; then + [[ -n "$curve" ]] && curve="($curve)" + if [[ "$what_dh" == "ECDH" ]]; then + pr_ecdh_quality "$bits" "$(printf -- "%-12s" "$bits bit $what_dh") $curve" + else + pr_dh_quality "$bits" "$(printf -- "%-12s" "$bits bit $what_dh") $curve" + fi + elif "$HAS_DH_BITS" || ( "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] ); then + out "No FS" + fi + outln + if [[ -n "${warning[i]}" ]]; then + out " " + outln "${warning[i]}" + fi + fileout "client_${short[i]}" "INFO" \ + "$(strip_spaces "${names[i]}") client simulation: $proto $cipher ${warning[i]}" + debugme cat $TMPFILE + fi + fi # correct service? + fi #current? i=$((i+1)) done tmpfile_handle $FUNCNAME.txt diff --git a/utils/update_client_sim_data.pl b/utils/update_client_sim_data.pl new file mode 100755 index 0000000..1613916 --- /dev/null +++ b/utils/update_client_sim_data.pl @@ -0,0 +1,341 @@ +#!/usr/bin/perl + +use strict; +use Data::Dumper; +use JSON; + +my $namelength = 30; + +my @spec; +my %ciphers; +foreach my $line ( split /\n/, `../bin/openssl.Linux.x86_64 ciphers -V 'ALL:COMPLEMENTOFALL:\@STRENGTH'`) { + my @fields = split /\s+/, $line; + my $hex = ""; + foreach my $byte ( split /,/, $fields[1] ) { + $byte = lc $byte; + $byte =~ s/^0x//; + $hex .= $byte; + } + $hex =~ s/^0+//; + $ciphers{hex "0x$hex"} = $fields[3]; +} + +# Get the data +my $json = `curl 'https://api.dev.ssllabs.com/api/v3/getClients'`; +my $ssllabs = decode_json($json); + +my %sims; +foreach my $client ( @$ssllabs ) { + # Shorts + my $has_matched = 1; + my $shortname = "$client->{name}_$client->{version}"; + $shortname =~ s/ /_/g; + $shortname =~ s/\.//g; + $shortname .= "_$client->{platform}" if exists $client->{platform}; + $shortname =~ s/[ \.]//g; + $shortname = lc($shortname); + + # Deduplicate + if ( ! exists $sims{$shortname} || $sims{$shortname}->{id} < $client->{id} ) { + my $sim = {}; + $sims{$shortname} = $sim; + $sim->{shortname} = "short+=(\"$shortname\")"; + + # Names + my $name = "$client->{name} $client->{version}"; + $name .= " $client->{platform}" if exists $client->{platform}; + # Get first namelength characters only + $name = substr($name . "" x $namelength,0,$namelength); + $sim->{name} = "names+=(\"$name\")"; + + # Ciphers + my @ciphers = (); + foreach my $suite ( @{$client->{suiteIds}} ) { + if ( exists $ciphers{$suite} ) { + push @ciphers, $ciphers{$suite}; } + elsif ( $suite == "255" ) { + # no openssl name for this: + if ( $has_matched ) { + print "Ignored: \"$shortname\" has" ; + $has_matched = 0; + } + print " \"0xFF\""; } + elsif ( $suite == "65279" ) { + # SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA + if ( $has_matched ) { + print "Ignored: \"$shortname\" has" ; + $has_matched = 0; + } + print " \"0xFEFF\""; } + elsif ( $suite == "52392" ) { + push @ciphers, "ECDHE-RSA-CHACHA20-POLY1305"; } + elsif ( $suite == "52393" ) { + push @ciphers, "ECDHE-ECDSA-CHACHA20-POLY1305"; } + elsif ( $suite == "52394" ) { + push @ciphers, "DHE-RSA-CHACHA20-POLY1305"; } + else { + print "ALERT: "; + if ( $has_matched ) { + print " \"$shortname\" has "; + $has_matched = 0; + } + print "$suite. Please FIXME "; + } + } + print "\n" if ! $has_matched ; + $sim->{ciphers} = "ciphers+=(\"" . (join ":", @ciphers) . "\")"; + + # SNI + if ( exists $client->{supportsSni} && $client->{supportsSni} ) { + $sim->{sni} = "sni+=(\"\$SNI\")"; + } else { + $sim->{sni} = "sni+=(\"\")"; + } + + # warning (if needed) + $sim->{warning} = "warning+=(\"\")"; + + # Handshake + if ( exists $client->{hexHandshakeBytes} ) { + $sim->{handshakebytes} = "handshakebytes+=(\"$client->{hexHandshakeBytes}\")"; + } else { + $sim->{handshakebytes} = "handshakebytes+=(\"\")"; + } + + # protos + my @proto_flags = (); + my @tls_flags = (); + # Figure out if we need to support sslv2 + if ( $client->{lowestProtocol} < 768 && $client->{highestProtocol} >= 512 ) { + # 512 = 0x200 = sslv2 + # 768 = 0x300 = sslv3 + push @proto_flags, "-ssl2"; + } + # Do we need to support SSL3? + if ( $client->{lowestProtocol} <= 768 && $client->{highestProtocol} >= 768 ) { + # 768 = 0x300 = sslv3 + push @proto_flags, "-ssl3"; + } + # Do we need to support TLS 1.0? + if ( $client->{lowestProtocol} <= 769 && $client->{highestProtocol} >= 769 ) { + # 769 = 0x301 = tls1.0 + push @proto_flags, "-tls1"; + } + # Do we need to support TLS 1.1? + if ( $client->{lowestProtocol} <= 770 && $client->{highestProtocol} >= 770 ) { + # 770 = 0x302 = tls1.1 + push @proto_flags, "-tls1_1"; + } + # Do we need to support TLS 1.2? + if ( $client->{lowestProtocol} <= 771 && $client->{highestProtocol} >= 771 ) { + # 771 = 0x303 = tls1.2 + push @proto_flags, "-tls1_2"; + } + $sim->{protos} = "protos+=(\"" . (join " ", reverse @proto_flags) . "\")"; + $sim->{lowestProtocol} = sprintf("lowest_protocol+=(\"0x%04x\")", $client->{lowestProtocol}); + $sim->{highestProtocol} = sprintf("highest_protocol+=(\"0x%04x\")", $client->{highestProtocol}); + + if ( lc($client->{name}) eq "java" || lc($client->{name}) eq "openssl" ) { + # Java and OpenSSL are generic clients + $sim->{service} = "service+=(\"ANY\")"; + } elsif ( $shortname =~ /^apple_ats/ ) { + # Apple ATS is HTTP(s) only + $sim->{service} = "service+=(\"HTTP\")"; + } else { + # All others are HTTP(s)/FTP only + $sim->{service} = "service+=(\"HTTP,FTP\")"; + } + + # Bit size limitations + $sim->{minDhBits} = "minDhBits+=($client->{minDhBits})"; + $sim->{maxDhBits} = "maxDhBits+=($client->{maxDhBits})"; + $sim->{minRsaBits} = "minRsaBits+=($client->{minRsaBits})"; + $sim->{maxRsaBits} = "maxRsaBits+=($client->{maxRsaBits})"; + $sim->{minEcdsaBits} = "minEcdsaBits+=($client->{minEcdsaBits})"; + if ( defined $client->{requiresSha2} && $client->{requiresSha2} ) { + $sim->{requiresSha2} = "requiresSha2+=(true)"; + } else { + $sim->{requiresSha2} = "requiresSha2+=(false)"; + } + } +} + +# +# This is where we maintain our own clients +my $sim = {}; +#$sim->{name} = "names+=(\"Mail iOS 9.3.2 \")"; +#$sim->{shortname} = "short+=(\"mail_ios_932\")"; +#$sim->{ciphers} = "ciphers+=(\"ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:RC4-SHA:RC4-MD5\")"; +#$sim->{sni} = "sni+=(\"\$SNI\")"; +#$sim->{warning} = "warning+=(\"\")"; +#$sim->{handshakebytes} = "handshakebytes+=(\"16030100bb010000b703015767e6ae46f9abf3138e26a9f9880f9697bf3387f7eff709db1fa220e692d80420fb04b0979bae1664e11ef172d4dfba15af59dd200b7831992a35c73cde9efed9003200ffc024c023c00ac009c008c028c027c014c013c012006b0067003900330016003d003c0035002f000ac007c011000500040100003c000000190017000014696d61702e73656374696f6e7a65726f2e6f7267000a00080006001700180019000b0002010000050005010000000000120000\")"; +#$sim->{protos} = "protos+=(\"#-tls1_1 -tls1\")"; +#$sim->{lowestProtocol} = "lowest_protocol+=(\"0x0300\")"; +#$sim->{highestProtocol} = "highest_protocol+=(\"0x0301\")"; +#$sim->{service} = "service+=(\"SMTP,POP,IMAP\")"; +#$sim->{minDhBits} = "minDhBits+=(-1)"; +#$sim->{maxDhBits} = "maxDhBits+=(-1)"; +#$sim->{minRsaBits} = "minRsaBits+=(-1)"; +#$sim->{maxRsaBits} = "maxRsaBits+=(-1)"; +#$sim->{minEcdsaBits} = "minEcdsaBits+=(-1)"; +#$sim->{requiresSha2} = "requiresSha2+=(false)"; +# +#$sim->{name} = "names+=(\"Mail OSX 10.11.15 \")"; +#$sim->{shortname} = "short+=(\"mail_osx_101115\")"; +#$sim->{ciphers} = "ciphers+=(\"ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:RC4-SHA:RC4-MD5\")"; +#$sim->{sni} = "sni+=(\"\$SNI\")"; +#$sim->{warning} = "warning+=(\"\")"; +#$sim->{handshakebytes} = "handshakebytes+=(\"16030100940100009003015770e928499e82df2eb7477200e2a828d9fa4109514385bd1602df44aaf2b0f400003200ffc024c023c00ac009c008c028c027c014c013c012006b0067003900330016003d003c0035002f000ac007c011000500040100003500000012001000000d3137382e3233372e33342e3932000a00080006001700180019000b0002010000050005010000000000120000\")"; +#$sim->{protos} = "protos+=(\"-tls1\")"; +#$sim->{lowestProtocol} = "lowest_protocol+=(\"0x0301\")"; +#$sim->{highestProtocol} = "highest_protocol+=(\"0x0301\")"; +#$sim->{service} = "service+=(\"SMTP,POP,IMAP\")"; +#$sim->{minDhBits} = "minDhBits+=(-1)"; +#$sim->{maxDhBits} = "maxDhBits+=(-1)"; +#$sim->{minRsaBits} = "minRsaBits+=(-1)"; +#$sim->{maxRsaBits} = "maxRsaBits+=(-1)"; +#$sim->{minEcdsaBits} = "minEcdsaBits+=(-1)"; +#$sim->{requiresSha2} = "requiresSha2+=(false)"; + +$sim->{name} = "names+=(\"Thunderbird 45.1.1 OSX 10.11 \")"; +$sim->{shortname} = "short+=(\"thunderbird_45.1.1_osx_101115\")"; +$sim->{ciphers} = "ciphers+=(\"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA\")"; +$sim->{sni} = "sni+=(\"\$SNI\")"; +$sim->{warning} = "warning+=(\"\")"; +$sim->{handshakebytes} = "handshakebytes+=(\"160301009d010000990303c7c5b3ff80b3aa597c770c538b98ae34a94c9590ad8f947ba7bc28692061cb57000016c02bc02fc00ac009c013c01400330039002f0035000a0100005a0000001800160000136d78332e73656374696f6e7a65726f2e6f7267ff01000100000a00080006001700180019000b0002010000230000000500050100000000000d001600140401050106010201040305030603020304020202\")"; +$sim->{protos} = "protos+=(\"-tls1_2 -tls1_1 -tls1\")"; +$sim->{lowestProtocol} = "lowest_protocol+=(\"0x0301\")"; +$sim->{highestProtocol} = "highest_protocol+=(\"0x0303\")"; +$sim->{service} = "service+=(\"SMTP,POP,IMAP\")"; +$sim->{minDhBits} = "minDhBits+=(-1)"; +$sim->{maxDhBits} = "maxDhBits+=(-1)"; +$sim->{minRsaBits} = "minRsaBits+=(-1)"; +$sim->{maxRsaBits} = "maxRsaBits+=(-1)"; +$sim->{minEcdsaBits} = "minEcdsaBits+=(-1)"; +$sim->{requiresSha2} = "requiresSha2+=(false)"; + +my %count; +foreach my $shortname ( reverse sort keys %sims ) { + if ( $shortname =~ /^baidu/ ) { + $count{baidu}++; + if ( $count{baidu} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^bing/) { + $count{bing}++; + if ( $count{bing} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^chrome/) { + $count{chrome}++; + if ( $count{chrome} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^firefox/) { + # Latest version + ESR releases + if ( $shortname =~ /ESR/ ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $count{firefox}++; + if ( $count{firefox} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } + } elsif ($shortname =~ /^googlebot/) { + $count{googlebot}++; + if ( $count{googlebot} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^tor/) { + $count{tor}++; + if ( $count{tor} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^yahoo/) { + $count{yahoo}++; + if ( $count{yahoo} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^yandex/) { + $count{yandex}++; + if ( $count{yandex} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^opera/) { + $count{opera}++; + if ( $count{opera} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^java 7/) { + $count{java7}++; + if ( $count{java7} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^java 8/) { + $count{java8}++; + if ( $count{java8} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^java/) { + # Other/older versions of java aren't current + $sims{$shortname}->{current} = "current+=(false)"; + } elsif ($shortname =~ /^openssl/) { + $count{openssl}++; + if ( $count{openssl} <= 1 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } elsif ($shortname =~ /^safari/) { + $count{safari}++; + if ( $count{safari} <= 2 ) { + $sims{$shortname}->{current} = "current+=(true)"; + } else { + $sims{$shortname}->{current} = "current+=(false)"; + } + } else { + # All versions are current + $sims{$shortname}->{current} = "current+=(true)"; + } +} + +open OUT, ">client-simulation-data.sh" or die "Unable to open client-simulation-data.sh"; +print OUT "#!/usr/bin/env bash + +# This file contains client handshake data used in the run_client_simulation function +# Don't update this file by hand, but run util/update_client_sim_data.pl instead + +# Most clients are taken from Qualys SSL Labs --- From: https://api.dev.ssllabs.com/api/v3/getClients +"; +foreach my $shortname ( sort keys %sims ) { + foreach my $k ( qw(name shortname ciphers sni warning handshakebytes protos lowestProtocol highestProtocol service + minDhBits maxDhBits minRsaBits maxRsaBits minEcdsaBits requiresSha2 current) ) { + print OUT " $sims{$shortname}->{$k}\n"; + } + print OUT "\n"; +} +close OUT; + +exit; diff --git a/utils/wireshark2ciphers.pl b/utils/wireshark2ciphers.pl new file mode 100755 index 0000000..d272ced --- /dev/null +++ b/utils/wireshark2ciphers.pl @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +use strict; +use Data::Dumper; +use JSON; + +my $namelength = 30; + +# Get all ciphers first (sorry only works on 64 bit mac atm) +my @spec; +my %ciphers; +foreach my $line ( split /\n/, `bin/openssl.Darwin.x86_64 ciphers -V 'ALL:COMPLEMENTOFALL:\@STRENGTH'`) { + my @fields = split /\s+/, $line; + my $hex = ""; + foreach my $byte ( split /,/, $fields[1] ) { + $byte = lc $byte; + $byte =~ s/^0x//; + $hex .= $byte; + } + $hex =~ s/^0+//; + $ciphers{"0x$hex"} = $fields[3]; +} +#die Dumper \%ciphers; +#exit; + +my @ciphers = (); +while (<>) { + if ( /^\s*Cipher Suite\:/ ) { + /\((0x[0-9a-f]+)\)\s*$/; + my $n = $1; + $n =~ s/0x0*/0x/; + if ( $n && exists $ciphers{$n} ) { + push @ciphers, $ciphers{$n}; + } else { + print STDERR "No matching cipher for: $n on line\n$_" + } + } else { + print STDERR "Ignoring line $_" + } +} + +print "\n\n" . join ":", @ciphers; +print "\n"; \ No newline at end of file