diff --git a/README.md b/README.md index 651e846..808bfc9 100644 --- a/README.md +++ b/README.md @@ -44,38 +44,38 @@ Testing plain SSL/TLS: ``` linux $ ./cipherscan www.google.com:443 ................... -prio ciphersuite protocols pfs_keysize -1 ECDHE-RSA-CHACHA20-POLY1305 SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -2 ECDHE-RSA-AES128-GCM-SHA256 SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -3 ECDHE-RSA-RC4-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -4 ECDHE-RSA-AES128-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -5 AES128-GCM-SHA256 SSLv3,TLSv1,TLSv1.1,TLSv1.2 -6 RC4-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 -7 RC4-MD5 SSLv3,TLSv1,TLSv1.1,TLSv1.2 -8 ECDHE-RSA-AES256-GCM-SHA384 SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -9 ECDHE-RSA-AES256-SHA384 SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -10 ECDHE-RSA-AES256-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -11 AES256-GCM-SHA384 SSLv3,TLSv1,TLSv1.1,TLSv1.2 -12 AES256-SHA256 SSLv3,TLSv1,TLSv1.1,TLSv1.2 -13 AES256-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 -14 ECDHE-RSA-DES-CBC3-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -15 DES-CBC3-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 -16 ECDHE-RSA-AES128-SHA256 SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits -17 AES128-SHA256 SSLv3,TLSv1,TLSv1.1,TLSv1.2 -18 AES128-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 +prio ciphersuite protocols pubkey_size signature_algorithm trusted pfs_keysize +1 ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +2 ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +3 ECDHE-RSA-AES128-SHA TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +4 ECDHE-RSA-RC4-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +5 AES128-GCM-SHA256 TLSv1.2 2048 sha1WithRSAEncryption True +6 AES128-SHA256 TLSv1.2 2048 sha1WithRSAEncryption True +7 AES128-SHA TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True +8 RC4-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True +9 RC4-MD5 SSLv3,TLSv1,TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True +10 ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +11 ECDHE-RSA-AES256-SHA384 TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +12 ECDHE-RSA-AES256-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +13 AES256-GCM-SHA384 TLSv1.2 2048 sha1WithRSAEncryption True +14 AES256-SHA256 TLSv1.2 2048 sha1WithRSAEncryption True +15 AES256-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True +16 ECDHE-RSA-DES-CBC3-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits +17 DES-CBC3-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2 2048 sha1WithRSAEncryption True +18 ECDHE-RSA-AES128-SHA256 TLSv1.2 2048 sha1WithRSAEncryption True ECDH,P-256,256bits ``` Testing STARTTLS: ``` darwin $ ./cipherscan -o ./openssl-mine -starttls xmpp jabber.ccc.de:5222 ......... -prio ciphersuite protocols pfs_keysize -1 DHE-RSA-AES256-SHA SSLv3,TLSv1 DH,1024bits -2 AES256-SHA SSLv3,TLSv1 -3 EDH-RSA-DES-CBC3-SHA SSLv3,TLSv1 DH,1024bits -4 DES-CBC3-SHA SSLv3,TLSv1 -5 DHE-RSA-AES128-SHA SSLv3,TLSv1 DH,1024bits -6 AES128-SHA SSLv3,TLSv1 -7 RC4-SHA SSLv3,TLSv1 -8 RC4-MD5 SSLv3,TLSv1 +prio ciphersuite protocols pubkey_size signature_algorithm trusted pfs_keysize +1 DHE-RSA-AES256-SHA SSLv3,TLSv1 2048 sha1WithRSAEncryption False DH,1024bits +2 AES256-SHA SSLv3,TLSv1 2048 sha1WithRSAEncryption False +3 EDH-RSA-DES-CBC3-SHA SSLv3,TLSv1 2048 sha1WithRSAEncryption False DH,1024bits +4 DES-CBC3-SHA SSLv3,TLSv1 2048 sha1WithRSAEncryption False +5 DHE-RSA-AES128-SHA SSLv3,TLSv1 2048 sha1WithRSAEncryption False DH,1024bits +6 AES128-SHA SSLv3,TLSv1 2048 sha1WithRSAEncryption False +7 RC4-SHA SSLv3,TLSv1 2048 sha1WithRSAEncryption False +8 RC4-MD5 SSLv3,TLSv1 2048 sha1WithRSAEncryption False ``` diff --git a/cipherscan b/cipherscan index 4d861aa..ff8d321 100755 --- a/cipherscan +++ b/cipherscan @@ -8,6 +8,10 @@ DOBENCHMARK=0 BENCHMARKITER=30 OPENSSLBIN="$(dirname $0)/openssl" +CACERTS=${CACERTS:-/etc/pki/tls/certs/ca-bundle.crt} +if [ ! -e "$CACERTS" ]; then + echo "Warning: CA Certificates not found at $CACERTS, export CACERTS variable with location of your trust anchors" 1>&2 +fi CIPHERSUITE="ALL:COMPLEMENTOFALL" DEBUG=0 VERBOSE=0 @@ -64,6 +68,7 @@ test_cipher_on_target() { cipher="" protocols="" pfs="" + previous_cipher="" for tls_version in "-ssl2" "-ssl3" "-tls1" "-tls1_1" "-tls1_2" do debug echo \"quit\\n\" \| $sslcommand $tls_version @@ -71,10 +76,32 @@ test_cipher_on_target() { current_cipher=$(grep "New, " <<<"$tmp"|awk '{print $5}') current_pfs=$(grep 'Server Temp Key' <<<"$tmp"|awk '{print $4$5$6$7}') current_protocol=$(egrep "^\s+Protocol\s+:" <<<"$tmp"|awk '{print $3}') + current_pubkey=$(grep 'Server public key is ' <<<"$tmp"|awk '{print $5}') + if [ -z $current_pubkey ]; then + current_pubkey=0 + fi + current_sigalg=$(openssl x509 -noout -text 2>/dev/null <<<"$tmp"|grep Signature\ Algorithm | head -n 1 | awk '{print $3}') || current_sigalg="None" + grep 'Verify return code: 0 ' <<<"$tmp" >/dev/null + if [ $? -eq 0 ]; then + current_trusted="True" + else + current_trusted="False" + fi + if [ -z $current_sigalg ]; then + current_sigalg=None + fi if [[ -z "$current_protocol" || "$current_cipher" == '(NONE)' ]]; then # connection failed, try again with next TLS version continue + else + verbose "connection successful; protocol: $current_protocol, cipher: $current_cipher, previous cipher: $previous_cipher" fi + # handling of TLSv1.2 only cipher suites + if [ ! -z "$previous_cipher" ] && [ "$previous_cipher" != "$current_cipher" ] && [ "$current_cipher" != "0000" ]; then + unset protocols + fi + previous_cipher=$current_cipher + # connection succeeded, add TLS version to positive results if [ -z "$protocols" ]; then protocols=$current_protocol @@ -83,6 +110,9 @@ test_cipher_on_target() { fi cipher=$current_cipher pfs=$current_pfs + pubkey=$current_pubkey + sigalg=$current_sigalg + trusted=$current_trusted # grab the cipher and PFS key size done # if cipher is empty, that means none of the TLS version worked with @@ -94,13 +124,13 @@ test_cipher_on_target() { # if cipher contains NONE, the cipher wasn't accepted elif [ "$cipher" == '(NONE) ' ]; then - result="$cipher $protocols $pfs" + result="$cipher $protocols $pubkey $sigalg $trusted $pfs" verbose "handshake failed, server returned ciphersuite '$result'" return 1 # the connection succeeded else - result="$cipher $protocols $pfs" + result="$cipher $protocols $pubkey $sigalg $trusted $pfs" verbose "handshake succeeded, server returned ciphersuite '$result'" return 0 fi @@ -133,7 +163,11 @@ bench_cipher() { get_cipher_pref() { [ "$OUTPUTFORMAT" == "terminal" ] && [ $DEBUG -lt 1 ] && echo -n '.' local ciphersuite="$1" - local sslcommand="$OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite" + if [ -e $CACERTS ]; then + local sslcommand="$OPENSSLBIN s_client -CAfile $CACERTS $SCLIENTARGS -connect $TARGET -cipher $ciphersuite" + else + local sslcommand="$OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite" + fi verbose "Connecting to '$TARGET' with ciphersuite '$ciphersuite'" test_cipher_on_target "$sslcommand" local success=$? @@ -151,6 +185,10 @@ get_cipher_pref() { display_results_in_terminal() { # Display the results ctr=1 + local pubkey + local sigalg + local trusted + local different=False for cipher in "${cipherspref[@]}"; do pciph=$(echo $cipher|awk '{print $1}') if [ $DOBENCHMARK -eq 1 ]; then @@ -159,14 +197,37 @@ display_results_in_terminal() { else r="$ctr $cipher" fi + if [ $ctr -eq 1 ]; then + pubkey=$(awk '{print $3}' <<<$cipher) + sigalg=$(awk '{print $4}' <<<$cipher) + trusted=$(awk '{print $5}' <<<$cipher) + else + if [ "$pubkey" != "$(awk '{print $3}' <<<$cipher)" ]; then + different=True + fi + if [ "$sigalg" != "$(awk '{print $4}' <<<$cipher)" ]; then + different=True + fi + if [ "$trusted" != "$(awk '{print $5}' <<<$cipher)" ]; then + different=True + fi + fi results=("${results[@]}" "$r") ctr=$((ctr+1)) done if [ $DOBENCHMARK -eq 1 ]; then - header="prio ciphersuite protocols pfs_keysize avg_handshake_microsec" + if [ $different == "True" ]; then + header="prio ciphersuite protocols pubkey_size signature_algoritm trusted pfs_keysize avg_handshake_microsec" + else + header="prio ciphersuite protocols pfs_keysize avg_handshake_microsec" + fi else - header="prio ciphersuite protocols pfs_keysize" + if [ $different == "True" ]; then + header="prio ciphersuite protocols pubkey_size signature_algorithm trusted pfs_keysize" + else + header="prio ciphersuite protocols pfs_keysize" + fi fi ctr=0 for result in "${results[@]}"; do @@ -174,8 +235,20 @@ display_results_in_terminal() { echo $header ctr=$((ctr+1)) fi - echo $result|grep -v '(NONE)' + if [ $different == "True" ]; then + echo $result|grep -v '(NONE)' + else + echo $result|grep -v '(NONE)'|awk '{print $1 " " $2 " " $3 " " $7}' + fi done|column -t + echo + if [ $different != "True" ]; then + if [ "$trusted" == "True" ]; then + echo "Certificate: trusted, $pubkey bit, $sigalg signature" + else + echo "Certificate: UNTRUSTED, $pubkey bit, $sigalg signature" + fi + fi } @@ -187,7 +260,10 @@ display_results_in_json() { [ $ctr -gt 0 ] && echo -n ',' echo -n "{\"cipher\":\"$(echo $cipher|awk '{print $1}')\"," echo -n "\"protocols\":[\"$(echo $cipher|awk '{print $2}'|sed 's/,/","/g')\"]," - pfs=$(echo $cipher|awk '{print $3}') + echo -n "\"pubkey\":[\"$(echo $cipher|awk '{print $3}'|sed 's/,/","/g')\"]," + echo -n "\"sigalg\":[\"$(echo $cipher|awk '{print $4}'|sed 's/,/","/g')\"]," + echo -n "\"trusted\":\"$(echo $cipher|awk '{print $5}'|sed 's/,/","/g')\"," + pfs=$(echo $cipher|awk '{print $6}') [ "$pfs" == "" ] && pfs="None" echo -n "\"pfs\":\"$pfs\"}" ctr=$((ctr+1))