2
0
mirror of https://github.com/mozilla/cipherscan.git synced 2025-06-07 19:43:40 +02:00
This commit is contained in:
Olivier Paroz 2014-09-22 00:18:17 +00:00
commit ed50f3c400
2 changed files with 85 additions and 16 deletions

View File

@ -8,15 +8,18 @@ On Linux x86_64 run: ./cipherscan www.google.com:443
On any other *nix or *tux run: ./cipherscan -o /path/to/openssl www.google.com:443 On any other *nix or *tux run: ./cipherscan -o /path/to/openssl www.google.com:443
and watch. and watch.
The newer your version of openssl, the better results you'll get. Versions On FreeBSD, you will need the following ports: textproc/gnugrep and sysutils/coreutils
of OpenSSL below 1.0.1 don't support TLS1.2 ciphers, elliptic curves, etc... Build your own or test what your system's OpenSSL supports.
The newer your version of openssl, the better results you'll get. Versions of OpenSSL below 1.0.1 don't support TLS1.2 ciphers, elliptic curves, etc...
Version 1.0.2 gives extra information about the ciphers used for the key exchange.
Build your own or test what your system's OpenSSL supports.
Cipherscan should work fine on Linux, Mac OS X, Solaris, Illumos, SmartOS, OpenIndiana if you specify a an openssl binary with -o. Cipherscan should work fine on Linux, Mac OS X, Solaris, Illumos, SmartOS, OpenIndiana if you specify a an openssl binary with -o.
Build OpenSSL with ChaCha20-Poly1305 support (Optional) Build OpenSSL with ChaCha20-Poly1305 support (Optional)
------------------------------------------------------- -------------------------------------------------------
The OpenSSL binary in this repository is built for 64bit Linux. If you wish to build a version with the same features for your own platform, [the snapshot from the OpenSSL gitweb view](http://git.openssl.org/gitweb/?p=openssl.git;a=tree;h=161b23361778c155f9c174694b1db2506a2e0b52;hb=9a8646510b) and build it like this: The OpenSSL binary in this repository is built for 64bit Linux. If you wish to build a version with the same features for your own platform, you can use [this snapshot from the OpenSSL gitweb view](http://git.openssl.org/gitweb/?p=openssl.git;a=tree;h=161b23361778c155f9c174694b1db2506a2e0b52;hb=9a8646510b) or [this Github repository](https://github.com/PeterMosmans/openssl) and build it like this:
``` ```
./config no-shared ./config no-shared
@ -226,3 +229,4 @@ Contributors
* Pepi Zawodsky <git@maclemon.at> * Pepi Zawodsky <git@maclemon.at>
* Michael Zeltner <m@niij.org> * Michael Zeltner <m@niij.org>
* Simon Deziel <simon.deziel@gmail.com> * Simon Deziel <simon.deziel@gmail.com>
* Olivier Paroz <opa-github@interfasys.ch>

View File

@ -4,12 +4,22 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this # License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Author: Julien Vehent [:ulfr] - 2013 # Author: Julien Vehent [:ulfr] - 2013
#
# Modified by Olivier Paroz in September 2014
#
# On FreeBSD, you will need the following ports: textproc/gnugrep and sysutils/coreutils
#
OS=`uname`
DOBENCHMARK=0 DOBENCHMARK=0
BENCHMARKITER=30 BENCHMARKITER=30
TIMEOUTBIN=timeout
if [ "${OS}" = "FreeBSD" ]; then
TIMEOUTBIN=gtimeout
fi
OPENSSLBIN="$(dirname $0)/openssl" OPENSSLBIN="$(dirname $0)/openssl"
if [ -z "$CACERTS" ]; then if [ -z "$CACERTS" ]; then
for f in /etc/pki/tls/certs/ca-bundle.crt /etc/ssl/certs/ca-certificates.crt; do for f in /etc/pki/tls/certs/ca-bundle.crt /etc/ssl/certs/ca-certificates.crt /usr/local/share/certs/ca-root-nss.crt; do
if [ -e "$f" ]; then if [ -e "$f" ]; then
CACERTS="$f" CACERTS="$f"
break break
@ -29,6 +39,7 @@ DELAY=0
ALLCIPHERS=0 ALLCIPHERS=0
OUTPUTFORMAT="terminal" OUTPUTFORMAT="terminal"
TIMEOUT=10 TIMEOUT=10
SNISCAN=0
usage() { usage() {
@ -36,7 +47,11 @@ usage() {
usage: $0 -h|--help usage: $0 -h|--help
$0 attempts to connect to a target site using all the ciphersuites it knows. $0 attempts to connect to a target site using all the ciphersuites it knows.
Julien Vehent [:ulfr] - https://github.com/jvehent/cipherscan
Original script by Julien Vehent. [:ulfr] - https://github.com/jvehent/cipherscan
FreeBSD version by Olivier Paroz - https://github.com/oparoz/cipherscan
On FreeBSD, you will need the following ports on FreeBSD: textproc/gnugrep and sysutils/coreutils
Port defaults to 443 Port defaults to 443
@ -51,6 +66,7 @@ Use one of the options below:
-h | --help Shows this help text. -h | --help Shows this help text.
-j | --json Output results in JSON format. -j | --json Output results in JSON format.
-o | --openssl path/to/your/openssl binary you want to use. -o | --openssl path/to/your/openssl binary you want to use.
-s | --sni Activates SNI
-v | --verbose Increase verbosity. -v | --verbose Increase verbosity.
The rest of the arguments will be interpreted as openssl s_client argument. The rest of the arguments will be interpreted as openssl s_client argument.
@ -92,8 +108,13 @@ test_cipher_on_target() {
fi fi
# filter out the OCSP server certificate # filter out the OCSP server certificate
tmp=$(awk 'BEGIN { pr="yes" } /^======================================/ { if ( pr=="yes" ) pr="no"; else pr="yes" } { if ( pr == "yes" ) print }' <<<"$tmp") tmp=$(awk 'BEGIN { pr="yes" } /^======================================/ { if ( pr=="yes" ) pr="no"; else pr="yes" } { if ( pr == "yes" ) print }' <<<"$tmp")
current_certcn=$(grep "subject=" <<<"$tmp"| grep -oP "(?<=CN\=)[^ |\/]+")
current_subjaltnames=$(${OPENSSLBIN} x509 -noout -text 2>/dev/null <<<"$tmp"|awk '/X509v3 Subject Alternative Name/ {getline;gsub(/ /, "", $0);print}' | tr -d "DNS:")
current_cipher=$(grep "New, " <<<"$tmp"|awk '{print $5}') current_cipher=$(grep "New, " <<<"$tmp"|awk '{print $5}')
current_pfs=$(grep 'Server Temp Key' <<<"$tmp"|awk '{print $4$5$6$7}') current_pfs=$(grep 'Server Temp Key' <<<"$tmp"|awk '{print $4$5$6$7}')
if [ -z $current_pfs ]; then
current_pfs="None"
fi
current_protocol=$(egrep "^\s+Protocol\s+:" <<<"$tmp"|awk '{print $3}') current_protocol=$(egrep "^\s+Protocol\s+:" <<<"$tmp"|awk '{print $3}')
current_pubkey=$(grep 'Server public key is ' <<<"$tmp"|awk '{print $5}') current_pubkey=$(grep 'Server public key is ' <<<"$tmp"|awk '{print $5}')
if [ -z $current_pubkey ]; then if [ -z $current_pubkey ]; then
@ -131,6 +152,16 @@ test_cipher_on_target() {
else else
protocols="$protocols,$current_protocol" protocols="$protocols,$current_protocol"
fi fi
certcns="$current_certcn"
# Let's add the alternative subject names if they exist
if [ -n "$current_subjaltnames" ]; then
IFS=',' read -ra subjaltnamesarray <<<"$current_subjaltnames"
for altname in "${subjaltnamesarray[@]}"; do
if [[ "$altname" != "$current_certcn" ]]; then
certcns="$certcns,$altname"
fi
done
fi
cipher=$current_cipher cipher=$current_cipher
pfs=$current_pfs pfs=$current_pfs
pubkey=$current_pubkey pubkey=$current_pubkey
@ -149,13 +180,13 @@ test_cipher_on_target() {
# if cipher contains NONE, the cipher wasn't accepted # if cipher contains NONE, the cipher wasn't accepted
elif [ "$cipher" == '(NONE) ' ]; then elif [ "$cipher" == '(NONE) ' ]; then
result="$cipher $protocols $pubkey $sigalg $trusted $tickethint $ocspstaple $pfs" result="$cipher $protocols $pubkey $sigalg $trusted $tickethint $ocspstaple $pfs $certcns"
verbose "handshake failed, server returned ciphersuite '$result'" verbose "handshake failed, server returned ciphersuite '$result'"
return 1 return 1
# the connection succeeded # the connection succeeded
else else
result="$cipher $protocols $pubkey $sigalg $trusted $tickethint $ocspstaple $pfs" result="$cipher $protocols $pubkey $sigalg $trusted $tickethint $ocspstaple $pfs $certcns"
verbose "handshake succeeded, server returned ciphersuite '$result'" verbose "handshake succeeded, server returned ciphersuite '$result'"
return 0 return 0
fi fi
@ -165,7 +196,7 @@ test_cipher_on_target() {
# Calculate the average handshake time for a specific ciphersuite # Calculate the average handshake time for a specific ciphersuite
bench_cipher() { bench_cipher() {
local ciphersuite="$1" local ciphersuite="$1"
local sslcommand="timeout $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite" local sslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
local t="$(date +%s%N)" local t="$(date +%s%N)"
verbose "Benchmarking handshake on '$TARGET' with ciphersuite '$ciphersuite'" verbose "Benchmarking handshake on '$TARGET' with ciphersuite '$ciphersuite'"
for i in $(seq 1 $BENCHMARKITER); do for i in $(seq 1 $BENCHMARKITER); do
@ -189,9 +220,9 @@ get_cipher_pref() {
[ "$OUTPUTFORMAT" == "terminal" ] && [ $DEBUG -lt 1 ] && echo -n '.' [ "$OUTPUTFORMAT" == "terminal" ] && [ $DEBUG -lt 1 ] && echo -n '.'
local ciphersuite="$1" local ciphersuite="$1"
if [ -e $CACERTS ]; then if [ -e $CACERTS ]; then
local sslcommand="timeout $TIMEOUT $OPENSSLBIN s_client -CAfile $CACERTS -status $SCLIENTARGS -connect $TARGET -cipher $ciphersuite" local sslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client -CAfile $CACERTS -status $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
else else
local sslcommand="timeout $TIMEOUT $OPENSSLBIN s_client -status $SCLIENTARGS -connect $TARGET -cipher $ciphersuite" local sslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client -status $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
fi fi
verbose "Connecting to '$TARGET' with ciphersuite '$ciphersuite'" verbose "Connecting to '$TARGET' with ciphersuite '$ciphersuite'"
test_cipher_on_target "$sslcommand" test_cipher_on_target "$sslcommand"
@ -210,6 +241,7 @@ get_cipher_pref() {
display_results_in_terminal() { display_results_in_terminal() {
# Display the results # Display the results
ctr=1 ctr=1
local certcns
local pubkey local pubkey
local sigalg local sigalg
local trusted local trusted
@ -230,6 +262,7 @@ display_results_in_terminal() {
trusted=$(awk '{print $5}' <<<$cipher) trusted=$(awk '{print $5}' <<<$cipher)
tickethint=$(awk '{print $6}' <<<$cipher) tickethint=$(awk '{print $6}' <<<$cipher)
ocspstaple=$(awk '{print $7}' <<<$cipher) ocspstaple=$(awk '{print $7}' <<<$cipher)
certcns=$(awk '{print $9}' <<<$cipher)
else else
if [ "$pubkey" != "$(awk '{print $3}' <<<$cipher)" ]; then if [ "$pubkey" != "$(awk '{print $3}' <<<$cipher)" ]; then
different=True different=True
@ -275,11 +308,28 @@ display_results_in_terminal() {
fi fi
done|column -t done|column -t
echo echo
matchhostname=0
hostcertcn="Not a match"
if [ -z "$certcns" ]; then
hostcertcn="CN not found"
else
IFS=',' read -ra certcnsarray <<<"$certcns"
for certcn in "${certcnsarray[@]}"; do
if [[ "$certcn" == "$HOST" ]]; then
matchhostname=1
hostcertcn="$certcn"
break
fi
done
fi
if [ $different != "True" ]; then if [ $different != "True" ]; then
if [ "$trusted" == "True" ]; then if [ "$trusted" == "True" ]; then
echo "Certificate: trusted, $pubkey bit, $sigalg signature" echo "Certificate: $hostcertcn, trusted, $pubkey bit, $sigalg signature"
else else
echo "Certificate: UNTRUSTED, $pubkey bit, $sigalg signature" echo "Certificate: $hostcertcn, UNTRUSTED, $pubkey bit, $sigalg signature"
fi fi
echo "TLS ticket lifetime hint: $tickethint" echo "TLS ticket lifetime hint: $tickethint"
fi fi
@ -288,6 +338,13 @@ display_results_in_terminal() {
else else
echo "OCSP stapling: not supported" echo "OCSP stapling: not supported"
fi fi
if [ $matchhostname -eq 0 ]; then
echo "WARNING - None of the CNs match the hostname given"
fi
if [ -n "$certcns" ]; then
echo "Here is the list of common names found in the certificate"
echo $certcns
fi
} }
@ -299,6 +356,7 @@ display_results_in_json() {
[ $ctr -gt 0 ] && echo -n ',' [ $ctr -gt 0 ] && echo -n ','
echo -n "{\"cipher\":\"$(echo $cipher|awk '{print $1}')\"," echo -n "{\"cipher\":\"$(echo $cipher|awk '{print $1}')\","
echo -n "\"protocols\":[\"$(echo $cipher|awk '{print $2}'|sed 's/,/","/g')\"]," echo -n "\"protocols\":[\"$(echo $cipher|awk '{print $2}'|sed 's/,/","/g')\"],"
echo -n "\"certcns\":[\"$(echo $cipher|awk '{print $9}'|sed 's/,/","/g')\"],"
echo -n "\"pubkey\":[\"$(echo $cipher|awk '{print $3}'|sed 's/,/","/g')\"]," echo -n "\"pubkey\":[\"$(echo $cipher|awk '{print $3}'|sed 's/,/","/g')\"],"
echo -n "\"sigalg\":[\"$(echo $cipher|awk '{print $4}'|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')\"," echo -n "\"trusted\":\"$(echo $cipher|awk '{print $5}'|sed 's/,/","/g')\","
@ -324,6 +382,10 @@ do
OPENSSLBIN=$2 # You might want to check if you really got FILE OPENSSLBIN=$2 # You might want to check if you really got FILE
shift 2 shift 2
;; ;;
-s | --sni)
SNISCAN=1
shift
;;
-a | --allciphers) -a | --allciphers)
ALLCIPHERS=1 ALLCIPHERS=1
shift shift
@ -387,8 +449,11 @@ debug "Port: $PORT"
TARGET=$HOST:$PORT TARGET=$HOST:$PORT
debug "target: $TARGET" debug "target: $TARGET"
SNIPARAM=""
SCLIENTARGS=$(sed -e s,${TEMPTARGET},,<<<"${@}") if [ $SNISCAN -gt 0 ]; then
SNIPARAM="-servername ${HOST}"
fi
SCLIENTARGS="$SNIPARAM $(sed -e s,${TEMPTARGET},,<<<"${@}")"
debug "sclientargs: $SCLIENTARGS" debug "sclientargs: $SCLIENTARGS"
@ -410,7 +475,7 @@ if [ $ALLCIPHERS -gt 0 ]; then
echo; echo "All accepted ciphersuites" echo; echo "All accepted ciphersuites"
for c in $($OPENSSLBIN ciphers -v ALL:COMPLEMENTOFALL 2>/dev/null |awk '{print $1}'|sort|uniq); do for c in $($OPENSSLBIN ciphers -v ALL:COMPLEMENTOFALL 2>/dev/null |awk '{print $1}'|sort|uniq); do
r="fail" r="fail"
osslcommand="timeout $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $c" osslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $c"
test_cipher_on_target "$osslcommand" test_cipher_on_target "$osslcommand"
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
r="pass" r="pass"