mirror of
https://github.com/mozilla/cipherscan.git
synced 2024-11-22 22:33:40 +01:00
62808a33c8
the certificate extracted in the above way will contain some junk from openssl s_client output we don't want like verification status we can remove it ro reduce disk usage for saved certificates
636 lines
21 KiB
Bash
Executable File
636 lines
21 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# 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/.
|
|
# Authors: Julien Vehent [:ulfr] - 201{3,4}
|
|
# Hubert Kario - 2014
|
|
|
|
# vim: autoindent tabstop=4 shiftwidth=4 expandtab softtabstop=4 filetype=sh
|
|
|
|
DOBENCHMARK=0
|
|
BENCHMARKITER=30
|
|
OPENSSLBIN="$(dirname $0)/openssl"
|
|
|
|
# test that timeout or gtimeout (darwin) are present
|
|
TIMEOUTBIN="$(which timeout)"
|
|
if [ "$TIMEOUTBIN" == "" ]; then
|
|
TIMEOUTBIN="$(which gtimeout)"
|
|
if [ "$TIMEOUTBIN" == "" ]; then
|
|
echo "neither timeout nor gtimeout are present. install coreutils with {apt-get,yum,brew} install coreutils"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# find a list of trusted CAs on the local system, or use the provided list
|
|
if [ -z "$CACERTS" ]; then
|
|
for f in /etc/pki/tls/certs/ca-bundle.crt /etc/ssl/certs/ca-certificates.crt; do
|
|
if [ -e "$f" ]; then
|
|
CACERTS="$f"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
if [ ! -e "$CACERTS" ]; then
|
|
CACERTS="$(dirname $0)/ca-bundle.crt"
|
|
fi
|
|
|
|
# RSA ciphers are put at the end to force Google servers to accept ECDSA ciphers
|
|
# (probably a result of a workaround for the bug in Apple implementation of ECDSA)
|
|
CIPHERSUITE="ALL:COMPLEMENTOFALL:+aRSA"
|
|
DEBUG=0
|
|
VERBOSE=0
|
|
DELAY=0
|
|
ALLCIPHERS=0
|
|
OUTPUTFORMAT="terminal"
|
|
TIMEOUT=30
|
|
# place where to put the found intermediate CA certificates and where
|
|
# trust anchors are stored
|
|
CAPATH=""
|
|
SAVECRT=""
|
|
|
|
# because running external commands like sleep incurs a fork penalty, we
|
|
# first check if it is necessary
|
|
ratelimit() {
|
|
if [[ $DELAY != "0" ]]; then
|
|
sleep $DELAY
|
|
fi
|
|
}
|
|
|
|
usage() {
|
|
echo -e "usage: $0 [-a|--allciphers] [-b|--benchmark] [--capath directory] [--saveca] [--savecrt directory] [-d|--delay seconds] [-D|--debug] [-j|--json] [-v|--verbose] [-o|--openssl file] [openssl s_client args] <target:port>
|
|
usage: $0 -h|--help
|
|
|
|
$0 attempts to connect to a target site using all the ciphersuites it knows.
|
|
Julien Vehent [:ulfr] - https://github.com/jvehent/cipherscan
|
|
|
|
Port defaults to 443
|
|
|
|
example: $ $0 www.google.com:443
|
|
|
|
Use one of the options below:
|
|
|
|
-a | --allciphers Test all known ciphers individually at the end.
|
|
-b | --benchmark Activate benchmark mode.
|
|
--capath use CAs from directory (must be in OpenSSL CAdir format)
|
|
--saveca save intermediate certificates in CA directory
|
|
-d | --delay Pause for n seconds between connections
|
|
-D | --debug Output ALL the information.
|
|
-h | --help Shows this help text.
|
|
-j | --json Output results in JSON format.
|
|
-o | --openssl path/to/your/openssl binary you want to use.
|
|
--savecrt path where to save untrusted and leaf certificates
|
|
-v | --verbose Increase verbosity.
|
|
|
|
The rest of the arguments will be interpreted as openssl s_client argument.
|
|
This enables checking smtp/imap/pop3/ftp/xmpp via -starttls
|
|
|
|
EXAMPLES: $0 -starttls xmpp jabber.ccc.de:5222
|
|
"
|
|
}
|
|
|
|
verbose() {
|
|
if [ $VERBOSE != 0 ]; then
|
|
echo "$@" >&2
|
|
fi
|
|
}
|
|
|
|
debug(){
|
|
if [ $DEBUG == 1 ]; then
|
|
echo Debug: "$@" >&2
|
|
set -evx
|
|
fi
|
|
}
|
|
|
|
c_hash() {
|
|
local h=$(${OPENSSLBIN} x509 -hash -noout -in "$1/$2" 2>/dev/null)
|
|
for num in $(seq 0 100); do
|
|
if [[ $1/${h}.${num} -ef $2 ]]; then
|
|
# file already linked, ignore
|
|
break
|
|
fi
|
|
if [[ ! -e $1/${h}.${num} ]]; then
|
|
# file doesn't exist, create a link
|
|
pushd "$1" > /dev/null
|
|
ln -s "$2" "${h}.${num}"
|
|
popd > /dev/null
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Connect to a target host with the selected ciphersuite
|
|
test_cipher_on_target() {
|
|
local sslcommand=$@
|
|
cipher=""
|
|
local cmnd=""
|
|
protocols=""
|
|
pfs=""
|
|
previous_cipher=""
|
|
certificates=""
|
|
for tls_version in "-ssl2" "-ssl3" "-tls1" "-tls1_1" "-tls1_2"
|
|
do
|
|
# sslv2 client hello doesn't support SNI extension
|
|
# in SSLv3 mode OpenSSL just ignores the setting so it's ok
|
|
# -status exception is ignored in SSLv2, go figure
|
|
if [ "$tls_version" == "-ssl2" ]; then
|
|
cmnd=$(sed 's/-servername\ [^ ]*//'<<<$sslcommand)
|
|
else
|
|
cmnd=$sslcommand
|
|
fi
|
|
ratelimit
|
|
debug echo \"Q\" \| $cmnd $tls_version
|
|
local tmp=$(echo "Q" | $cmnd $tls_version 1>/dev/stdout 2>/dev/null)
|
|
if grep 'OCSP Response Data' <<<"$tmp" >/dev/null; then
|
|
current_ocspstaple="True"
|
|
else
|
|
current_ocspstaple="False"
|
|
fi
|
|
# filter out the OCSP server certificate
|
|
tmp=$(awk 'BEGIN { pr="yes" } /^======================================/ { if ( pr=="yes" ) pr="no"; else pr="yes" } { if ( pr == "yes" ) print }' <<<"$tmp")
|
|
|
|
# session metadata
|
|
current_cipher=$(awk '/New, / {print $5; exit}' <<<"$tmp")
|
|
current_pfs=$(awk '/Server Temp Key/ {print $4$5$6$7; exit}' <<<"$tmp")
|
|
current_protocol=$(awk '/^ +Protocol +:/ {print $3; exit}' <<<"$tmp")
|
|
current_tickethint=$(awk '/ticket lifetime hint/ {print $6; exit}' <<<"$tmp")
|
|
if [ -z $current_tickethint ]; then
|
|
current_tickethint=None
|
|
fi
|
|
|
|
# certificate metadata
|
|
current_pubkey=$(awk '/Server public key is / {print $5;exit}' <<<"$tmp")
|
|
if [ -z $current_pubkey ]; then
|
|
current_pubkey=0
|
|
fi
|
|
current_sigalg=$(${OPENSSLBIN} x509 -noout -text 2>/dev/null <<<"$tmp"|\
|
|
awk '/Signature Algorithm/ {print $3; exit}') || 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
|
|
|
|
# collect certificate data
|
|
current_certificates=""
|
|
local certificate_count=$(grep --count -- '-----END CERTIFICATE-----'\
|
|
<<<"$tmp")
|
|
debug "server presented $certificate_count certificates"
|
|
local i
|
|
for ((i=0; i<$certificate_count; i=i+1 )); do
|
|
|
|
# extract i'th certificate
|
|
local cert=$(awk -v i=$i 'split_after == 1 {n++;split_after=0}
|
|
/-----END CERTIFICATE-----/ {split_after=1}
|
|
{if (n == i) print }
|
|
' <<<"$tmp")
|
|
# clean up the cert from junk before BEGIN CERTIFICATE
|
|
cert=$(${OPENSSLBIN} x509 <<<"$cert" 2>/dev/null)
|
|
|
|
# compute sha256 fingerprint of the certificate
|
|
local sha256sum=$(${OPENSSLBIN} x509 -outform DER <<<"$cert" 2>/dev/null |\
|
|
${OPENSSLBIN} dgst -sha256 -r 2>/dev/null| awk '{print $1}')
|
|
|
|
# check if it is a CA certificate
|
|
local isCA="False"
|
|
if ${OPENSSLBIN} x509 -noout -text <<<"$cert" 2>/dev/null |\
|
|
grep 'CA:TRUE' >/dev/null; then
|
|
isCA="True"
|
|
fi
|
|
|
|
# build trust source for certificate verification
|
|
local trust_source=()
|
|
if [[ -n $CAPATH ]]; then
|
|
trust_source=("-CApath" "$CAPATH")
|
|
elif [[ -e $CACERTS ]]; then
|
|
trust_source=("-CAfile" "$CACERTS")
|
|
fi
|
|
|
|
# check if the certificate is actually trusted (server may present
|
|
# unrelated certificates that are not trusted (including self
|
|
# signed ones)
|
|
local saved="False"
|
|
if ${OPENSSLBIN} verify "${trust_source[@]}" \
|
|
-untrusted <(echo "$tmp") <(echo "$cert") 2>/dev/null | \
|
|
grep 'OK$' >/dev/null; then
|
|
|
|
# if the certificate is an intermediate CA it may be useful
|
|
# for connecting to servers that are misconfigured so save it
|
|
if [[ -n $CAPATH ]] && [[ $SAVECA == "True" ]] && [[ $isCA == "True" ]]; then
|
|
if [[ ! -e "$CAPATH/${sha256sum}.pem" ]]; then
|
|
echo "$cert" > "$CAPATH/${sha256sum}.pem"
|
|
c_hash "$CAPATH" "${sha256sum}.pem"
|
|
fi
|
|
saved="True"
|
|
fi
|
|
fi
|
|
if [[ -n $SAVECRT ]] && [[ $saved == "False" ]]; then
|
|
if [[ ! -e $SAVECRT/${sha256sum}.pem ]]; then
|
|
echo "$cert" > "$SAVECRT/${sha256sum}.pem"
|
|
fi
|
|
fi
|
|
# save the sha sum for reporting
|
|
if [ -n "${current_certificates}" ]; then
|
|
current_certificates+=","
|
|
fi
|
|
current_certificates+="\"${sha256sum}\""
|
|
done
|
|
debug "current_certificates: $current_certificates"
|
|
|
|
# parsing finished, report result
|
|
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
|
|
else
|
|
protocols="$protocols,$current_protocol"
|
|
fi
|
|
cipher=$current_cipher
|
|
pfs=$current_pfs
|
|
pubkey=$current_pubkey
|
|
sigalg=$current_sigalg
|
|
trusted=$current_trusted
|
|
tickethint=$current_tickethint
|
|
ocspstaple=$current_ocspstaple
|
|
certificates="$current_certificates"
|
|
# grab the cipher and PFS key size
|
|
done
|
|
# if cipher is empty, that means none of the TLS version worked with
|
|
# the current cipher
|
|
if [ -z "$cipher" ]; then
|
|
verbose "handshake failed, no ciphersuite was returned"
|
|
result='ConnectionFailure'
|
|
return 2
|
|
|
|
# if cipher contains NONE, the cipher wasn't accepted
|
|
elif [ "$cipher" == '(NONE) ' ]; then
|
|
result="$cipher $protocols $pubkey $sigalg $trusted $tickethint $ocspstaple $pfs"
|
|
verbose "handshake failed, server returned ciphersuite '$result'"
|
|
return 1
|
|
|
|
# the connection succeeded
|
|
else
|
|
result="$cipher $protocols $pubkey $sigalg $trusted $tickethint $ocspstaple $pfs"
|
|
verbose "handshake succeeded, server returned ciphersuite '$result'"
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
# Calculate the average handshake time for a specific ciphersuite
|
|
bench_cipher() {
|
|
local ciphersuite="$1"
|
|
local sslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
|
|
local t="$(date +%s%N)"
|
|
verbose "Benchmarking handshake on '$TARGET' with ciphersuite '$ciphersuite'"
|
|
for i in $(seq 1 $BENCHMARKITER); do
|
|
debug Connection $i
|
|
(echo "Q" | $sslcommand 2>/dev/null 1>/dev/null)
|
|
if [ $? -gt 0 ]; then
|
|
break
|
|
fi
|
|
done
|
|
# Time interval in nanoseconds
|
|
local t="$(($(date +%s%N) - t))"
|
|
verbose "Benchmarking done in $t nanoseconds"
|
|
# Microseconds
|
|
cipherbenchms="$((t/1000/$BENCHMARKITER))"
|
|
}
|
|
|
|
# Connect to the target and retrieve the chosen cipher
|
|
# recursively until the connection fails
|
|
get_cipher_pref() {
|
|
[ "$OUTPUTFORMAT" == "terminal" ] && [ $DEBUG -lt 1 ] && echo -n '.'
|
|
local ciphersuite="$1"
|
|
|
|
local sslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client"
|
|
if [ -n "$CAPATH" ]; then
|
|
sslcommand+=" -CApath $CAPATH -showcerts"
|
|
elif [ -e $CACERTS ]; then
|
|
sslcommand+=" -CAfile $CACERTS"
|
|
fi
|
|
sslcommand+=" -status $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
|
|
|
|
verbose "Connecting to '$TARGET' with ciphersuite '$ciphersuite'"
|
|
test_cipher_on_target "$sslcommand"
|
|
local success=$?
|
|
# If the connection succeeded with the current cipher, benchmark and store
|
|
if [ $success -eq 0 ]; then
|
|
cipherspref=("${cipherspref[@]}" "$result")
|
|
ciphercertificates=("${ciphercertificates[@]}" "$certificates")
|
|
pciph=$(echo $result|awk '{print $1}')
|
|
get_cipher_pref "!$pciph:$ciphersuite"
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
display_results_in_terminal() {
|
|
# Display the results
|
|
ctr=1
|
|
local pubkey
|
|
local sigalg
|
|
local trusted
|
|
local tickethint
|
|
local ocspstaple
|
|
local different=False
|
|
echo "Target: $TARGET"; echo
|
|
for cipher in "${cipherspref[@]}"; do
|
|
pciph=$(echo $cipher|awk '{print $1}')
|
|
if [ $DOBENCHMARK -eq 1 ]; then
|
|
bench_cipher "$pciph"
|
|
r="$ctr $cipher $cipherbenchms"
|
|
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)
|
|
tickethint=$(awk '{print $6}' <<<$cipher)
|
|
ocspstaple=$(awk '{print $7}' <<<$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
|
|
if [ "$tickethint" != "$(awk '{print $6}' <<<$cipher)" ]; then
|
|
different=True
|
|
fi
|
|
fi
|
|
results=("${results[@]}" "$r")
|
|
ctr=$((ctr+1))
|
|
done
|
|
|
|
if [ $DOBENCHMARK -eq 1 ]; then
|
|
if [ $different == "True" ]; then
|
|
header="prio ciphersuite protocols pubkey_size signature_algoritm trusted ticket_hint ocsp_staple pfs_keysize avg_handshake_microsec"
|
|
else
|
|
header="prio ciphersuite protocols pfs_keysize avg_handshake_microsec"
|
|
fi
|
|
else
|
|
if [ $different == "True" ]; then
|
|
header="prio ciphersuite protocols pubkey_size signature_algorithm trusted ticket_hint ocsp_staple pfs_keysize"
|
|
else
|
|
header="prio ciphersuite protocols pfs_keysize"
|
|
fi
|
|
fi
|
|
ctr=0
|
|
for result in "${results[@]}"; do
|
|
if [ $ctr -eq 0 ]; then
|
|
echo $header
|
|
ctr=$((ctr+1))
|
|
fi
|
|
if [ $different == "True" ]; then
|
|
echo $result|grep -v '(NONE)'
|
|
else
|
|
# prints priority, ciphersuite, protocols and pfs_keysize
|
|
echo $result|grep -v '(NONE)'|awk '{print $1 " " $2 " " $3 " " $9}'
|
|
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
|
|
echo "TLS ticket lifetime hint: $tickethint"
|
|
fi
|
|
if [[ $ocspstaple == "True" ]]; then
|
|
echo "OCSP stapling: supported"
|
|
else
|
|
echo "OCSP stapling: not supported"
|
|
fi
|
|
if [[ $serverside == "True" ]]; then
|
|
echo "Server side cipher ordering"
|
|
else
|
|
echo "Client side cipher ordering"
|
|
fi
|
|
}
|
|
|
|
display_results_in_json() {
|
|
# Display the results in json
|
|
ctr=0
|
|
echo -n "{\"target\":\"$TARGET\",\"utctimestamp\":\"$(date -u '+%FT%T.0Z')\",\"serverside\":\"${serverside}\",\"ciphersuite\": ["
|
|
for cipher in "${cipherspref[@]}"; do
|
|
[ $ctr -gt 0 ] && echo -n ','
|
|
echo -n "{\"cipher\":\"$(echo $cipher|awk '{print $1}')\","
|
|
echo -n "\"protocols\":[\"$(echo $cipher|awk '{print $2}'|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 "\"trusted\":\"$(echo $cipher|awk '{print $5}'|sed 's/,/","/g')\","
|
|
if [[ -n $CAPATH ]]; then
|
|
echo -n "\"certificates\":[${ciphercertificates[$ctr]}],"
|
|
fi
|
|
echo -n "\"ticket_hint\":\"$(echo $cipher|awk '{print $6}')\","
|
|
echo -n "\"ocsp_stapling\":\"$(echo $cipher|awk '{print $7}')\","
|
|
pfs=$(echo $cipher|awk '{print $8}')
|
|
[ "$pfs" == "" ] && pfs="None"
|
|
echo -n "\"pfs\":\"$pfs\"}"
|
|
ctr=$((ctr+1))
|
|
done
|
|
echo ']}'
|
|
}
|
|
|
|
test_serverside_ordering() {
|
|
local ciphersuite=""
|
|
local prefered=""
|
|
# server supports only one cipher or no ciphers, so it effectively uses server side ordering...
|
|
if [[ ${#cipherspref[@]} -lt 2 ]]; then
|
|
serverside="True"
|
|
return 0
|
|
# server supports just two ciphers, so rotate them, that should be enough
|
|
elif [[ ${#cipherspref[@]} -eq 2 ]]; then
|
|
|
|
local cipher=$(awk '{print $1}' <<< ${cipherspref[1]})
|
|
prefered="$cipher"
|
|
ciphersuite=$cipher
|
|
|
|
cipher=$(awk '{print $1}' <<< ${cipherspref[0]})
|
|
ciphersuite+=":$cipher"
|
|
|
|
# server supports 3 or more ciphers, rotate all three. This is necessary because google does
|
|
# select first client provided cipher, if it is either CDHE-RSA-AES128-GCM-SHA256 or
|
|
# ECDHE-RSA-CHACHA20-POLY1305
|
|
else
|
|
local cipher=$(awk '{print $1}' <<< ${cipherspref[2]})
|
|
prefered="$cipher"
|
|
ciphersuite="$cipher"
|
|
|
|
cipher=$(awk '{print $1}' <<< ${cipherspref[1]})
|
|
ciphersuite+=":$cipher"
|
|
|
|
cipher=$(awk '{print $1}' <<< ${cipherspref[0]})
|
|
ciphersuite+=":$cipher"
|
|
fi
|
|
|
|
local sslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client"
|
|
if [ -n "$CAPATH" ]; then
|
|
sslcommand+=" -CApath $CAPATH -showcerts"
|
|
elif [ -e "$CACERTS" ]; then
|
|
sslcommand+=" -CAfile $CACERTS"
|
|
fi
|
|
sslcommand+=" -status $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
|
|
|
|
test_cipher_on_target "$sslcommand"
|
|
if [ $? -ne 0 ]; then
|
|
serverside="True"
|
|
else
|
|
local selected=$(awk '{print $1}' <<< $result)
|
|
if [[ $selected == $prefered ]]; then
|
|
serverside="False"
|
|
else
|
|
serverside="True"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# UNKNOWNOPTIONS=""
|
|
while :
|
|
do
|
|
case $1 in
|
|
-h | --help | -\?)
|
|
usage
|
|
exit 0 # This is not an error, User asked help. Don't do "exit 1"
|
|
;;
|
|
-o | --openssl)
|
|
OPENSSLBIN=$2 # You might want to check if you really got FILE
|
|
shift 2
|
|
;;
|
|
-a | --allciphers)
|
|
ALLCIPHERS=1
|
|
shift
|
|
;;
|
|
-v | --verbose)
|
|
# Each instance of -v adds 1 to verbosity
|
|
VERBOSE=$((VERBOSE+1))
|
|
shift
|
|
;;
|
|
-j | -json | --json | --JSON)
|
|
OUTPUTFORMAT="json"
|
|
shift
|
|
;;
|
|
-b | --benchmark)
|
|
DOBENCHMARK=1
|
|
shift
|
|
;;
|
|
-D | --debug)
|
|
DEBUG=1
|
|
shift
|
|
;;
|
|
-d | --delay)
|
|
DELAY=$2
|
|
shift 2
|
|
;;
|
|
--capath)
|
|
CAPATH="$2"
|
|
shift 2
|
|
;;
|
|
--saveca)
|
|
SAVECA="True"
|
|
shift 1
|
|
;;
|
|
--savecrt)
|
|
SAVECRT="$2"
|
|
shift 2
|
|
;;
|
|
--) # End of all options
|
|
shift
|
|
break
|
|
;;
|
|
# -*)
|
|
# UNKNOWNOPTIONS=$((UNKNOWNOPTIONS+$1))
|
|
# # echo "WARN: Unknown option (ignored): $1" >&2
|
|
# shift
|
|
# ;;
|
|
*) # no more options we understand.
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ $VERBOSE != 0 ] ; then
|
|
[ -n "$CACERTS" ] && echo "Using trust anchors from $CACERTS"
|
|
echo "Loading $($OPENSSLBIN ciphers -v $CIPHERSUITE 2>/dev/null|grep Kx|wc -l) ciphersuites from $(echo -n $($OPENSSLBIN version 2>/dev/null))"
|
|
$OPENSSLBIN ciphers ALL 2>/dev/null
|
|
fi
|
|
|
|
# echo paramters left: $@
|
|
|
|
TEMPTARGET=$(sed -e 's/^.* //'<<<"${@}")
|
|
HOST=$(sed -e 's/:.*//'<<<"${TEMPTARGET}")
|
|
PORT=$(sed -e 's/.*://'<<<"${TEMPTARGET}")
|
|
|
|
# Default to https if no port given
|
|
if [ "$HOST" = "$PORT" ]; then
|
|
PORT=443
|
|
fi
|
|
|
|
debug "host: $HOST"
|
|
debug "Port: $PORT"
|
|
|
|
TARGET=$HOST:$PORT
|
|
debug "target: $TARGET"
|
|
|
|
# test our openssl is usable
|
|
tmp="$($OPENSSLBIN -h 2>&1 1>/dev/null)"
|
|
if [ $? -gt 0 ]; then
|
|
OPENSSLBIN=$(which openssl)
|
|
if [ "$OUTPUTFORMAT" == "terminal" ]; then
|
|
echo "custom openssl not executable, falling back to system one from $OPENSSLBIN"
|
|
fi
|
|
fi
|
|
|
|
SCLIENTARGS=$(sed -e s,${TEMPTARGET},,<<<"${@}")
|
|
debug "sclientargs: $SCLIENTARGS"
|
|
|
|
|
|
cipherspref=();
|
|
ciphercertificates=()
|
|
results=()
|
|
|
|
# Call to the recursive loop that retrieves the cipher preferences
|
|
get_cipher_pref $CIPHERSUITE
|
|
|
|
test_serverside_ordering
|
|
|
|
if [ "$OUTPUTFORMAT" == "json" ]; then
|
|
display_results_in_json
|
|
else
|
|
echo
|
|
display_results_in_terminal
|
|
fi
|
|
|
|
# If asked, test every single cipher individually
|
|
if [ $ALLCIPHERS -gt 0 ]; then
|
|
echo; echo "All accepted ciphersuites"
|
|
for c in $($OPENSSLBIN ciphers -v ALL:COMPLEMENTOFALL 2>/dev/null |awk '{print $1}'|sort|uniq); do
|
|
r="fail"
|
|
osslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $c"
|
|
test_cipher_on_target "$osslcommand"
|
|
if [ $? -eq 0 ]; then
|
|
r="pass"
|
|
fi
|
|
echo "$c $r"|awk '{printf "%-35s %s\n",$1,$2}'
|
|
done
|
|
fi
|