mirror of
https://github.com/drwetter/testssl.sh.git
synced 2025-01-08 09:40:57 +01:00
Merge branch '2.9dev' into openssl_location
This commit is contained in:
commit
e03d89107b
@ -16,6 +16,7 @@ my (
|
|||||||
pass("Running testssl.sh against badssl.com to create a baseline (may take 2~3 minutes)"); $tests++;
|
pass("Running testssl.sh against badssl.com to create a baseline (may take 2~3 minutes)"); $tests++;
|
||||||
my $okout = `./testssl.sh -S -e -U --jsonfile tmp.json --color 0 badssl.com`;
|
my $okout = `./testssl.sh -S -e -U --jsonfile tmp.json --color 0 badssl.com`;
|
||||||
my $okjson = json('tmp.json');
|
my $okjson = json('tmp.json');
|
||||||
|
unlink 'tmp.json';
|
||||||
cmp_ok(@$okjson,'>',10,"We have more then 10 findings"); $tests++;
|
cmp_ok(@$okjson,'>',10,"We have more then 10 findings"); $tests++;
|
||||||
|
|
||||||
# Expiration
|
# Expiration
|
||||||
@ -23,6 +24,7 @@ pass("Running testssl against expired.badssl.com"); $tests++;
|
|||||||
$out = `./testssl.sh -S --jsonfile tmp.json --color 0 expired.badssl.com`;
|
$out = `./testssl.sh -S --jsonfile tmp.json --color 0 expired.badssl.com`;
|
||||||
like($out, qr/Certificate Expiration\s+expired\!/,"The certificate should be expired"); $tests++;
|
like($out, qr/Certificate Expiration\s+expired\!/,"The certificate should be expired"); $tests++;
|
||||||
$json = json('tmp.json');
|
$json = json('tmp.json');
|
||||||
|
unlink 'tmp.json';
|
||||||
$found = 0;
|
$found = 0;
|
||||||
foreach my $f ( @$json ) {
|
foreach my $f ( @$json ) {
|
||||||
if ( $f->{id} eq "expiration" ) {
|
if ( $f->{id} eq "expiration" ) {
|
||||||
@ -39,6 +41,7 @@ pass("Running testssl against self-signed.badssl.com"); $tests++;
|
|||||||
$out = `./testssl.sh -S --jsonfile tmp.json --color 0 self-signed.badssl.com`;
|
$out = `./testssl.sh -S --jsonfile tmp.json --color 0 self-signed.badssl.com`;
|
||||||
like($out, qr/Certificate Expiration\s+\d+/,"The certificate should not be expired"); $tests++;
|
like($out, qr/Certificate Expiration\s+\d+/,"The certificate should not be expired"); $tests++;
|
||||||
$json = json('tmp.json');
|
$json = json('tmp.json');
|
||||||
|
unlink 'tmp.json';
|
||||||
$found = 0;
|
$found = 0;
|
||||||
foreach my $f ( @$json ) {
|
foreach my $f ( @$json ) {
|
||||||
if ( $f->{id} eq "expiration" ) {
|
if ( $f->{id} eq "expiration" ) {
|
||||||
@ -79,6 +82,7 @@ is($found,1,"We had a finding for this in the JSON output"); $tests++;
|
|||||||
#$out = `./testssl.sh -S --jsonfile tmp.json --color 0 wrong.host.badssl.com`;
|
#$out = `./testssl.sh -S --jsonfile tmp.json --color 0 wrong.host.badssl.com`;
|
||||||
#unlike($out, qr/Certificate Expiration\s+expired\!/,"The certificate should not be expired"); $tests++;
|
#unlike($out, qr/Certificate Expiration\s+expired\!/,"The certificate should not be expired"); $tests++;
|
||||||
#$json = json('tmp.json');
|
#$json = json('tmp.json');
|
||||||
|
#unlink 'tmp.json';
|
||||||
#$found = 0;
|
#$found = 0;
|
||||||
#foreach my $f ( @$json ) {
|
#foreach my $f ( @$json ) {
|
||||||
# if ( $f->{id} eq "expiration" ) {
|
# if ( $f->{id} eq "expiration" ) {
|
||||||
@ -95,6 +99,7 @@ pass("Running testssl against incomplete-chain.badssl.com"); $tests++;
|
|||||||
$out = `./testssl.sh -S --jsonfile tmp.json --color 0 incomplete-chain.badssl.com`;
|
$out = `./testssl.sh -S --jsonfile tmp.json --color 0 incomplete-chain.badssl.com`;
|
||||||
like($out, qr/Chain of trust.*?NOT ok\s+\(chain incomplete\)/,"Chain of trust should fail because of incomplete"); $tests++;
|
like($out, qr/Chain of trust.*?NOT ok\s+\(chain incomplete\)/,"Chain of trust should fail because of incomplete"); $tests++;
|
||||||
$json = json('tmp.json');
|
$json = json('tmp.json');
|
||||||
|
unlink 'tmp.json';
|
||||||
$found = 0;
|
$found = 0;
|
||||||
foreach my $f ( @$json ) {
|
foreach my $f ( @$json ) {
|
||||||
if ( $f->{id} eq "chain_of_trust" ) {
|
if ( $f->{id} eq "chain_of_trust" ) {
|
||||||
@ -113,6 +118,7 @@ is($found,1,"We had a finding for this in the JSON output"); $tests++;
|
|||||||
#$out = `./testssl.sh -e -U --jsonfile tmp.json --color 0 cbc.badssl.com`;
|
#$out = `./testssl.sh -e -U --jsonfile tmp.json --color 0 cbc.badssl.com`;
|
||||||
#like($out, qr/Chain of trust.*?NOT ok\s+\(chain incomplete\)/,"Chain of trust should fail because of incomplete"); $tests++;
|
#like($out, qr/Chain of trust.*?NOT ok\s+\(chain incomplete\)/,"Chain of trust should fail because of incomplete"); $tests++;
|
||||||
#$json = json('tmp.json');
|
#$json = json('tmp.json');
|
||||||
|
#unlink 'tmp.json';
|
||||||
#$found = 0;
|
#$found = 0;
|
||||||
#foreach my $f ( @$json ) {
|
#foreach my $f ( @$json ) {
|
||||||
# if ( $f->{id} eq "chain_of_trust" ) {
|
# if ( $f->{id} eq "chain_of_trust" ) {
|
||||||
@ -132,4 +138,4 @@ sub json($) {
|
|||||||
$file = `cat $file`;
|
$file = `cat $file`;
|
||||||
unlink $file;
|
unlink $file;
|
||||||
return from_json($file);
|
return from_json($file);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ $tests = 0;
|
|||||||
pass("Running testssl.sh against badssl.com to create a JSON report with severity level equal greater than LOW (may take 2~3 minutes)"); $tests++;
|
pass("Running testssl.sh against badssl.com to create a JSON report with severity level equal greater than LOW (may take 2~3 minutes)"); $tests++;
|
||||||
$out = `./testssl.sh -S -e -U --jsonfile tmp.json --severity LOW --color 0 badssl.com`;
|
$out = `./testssl.sh -S -e -U --jsonfile tmp.json --severity LOW --color 0 badssl.com`;
|
||||||
$json = json('tmp.json');
|
$json = json('tmp.json');
|
||||||
|
unlink 'tmp.json';
|
||||||
$found = 0;
|
$found = 0;
|
||||||
cmp_ok(@$json,'>',0,"At least 1 finding is expected"); $tests++;
|
cmp_ok(@$json,'>',0,"At least 1 finding is expected"); $tests++;
|
||||||
foreach my $f ( @$json ) {
|
foreach my $f ( @$json ) {
|
||||||
@ -33,6 +34,7 @@ is($found,0,"We should not have any finding with INFO level"); $tests++;
|
|||||||
pass("Running testssl.sh against badssl.com to create a JSON-PRETTY report with severity level equal greater than LOW (may take 2~3 minutes)"); $tests++;
|
pass("Running testssl.sh against badssl.com to create a JSON-PRETTY report with severity level equal greater than LOW (may take 2~3 minutes)"); $tests++;
|
||||||
$out = `./testssl.sh -S -e -U --jsonfile-pretty tmp.json --severity LOW --color 0 badssl.com`;
|
$out = `./testssl.sh -S -e -U --jsonfile-pretty tmp.json --severity LOW --color 0 badssl.com`;
|
||||||
$json_pretty = json('tmp.json');
|
$json_pretty = json('tmp.json');
|
||||||
|
unlink 'tmp.json';
|
||||||
$found = 0;
|
$found = 0;
|
||||||
my $vulnerabilities = $json_pretty->{scanResult}->[0]->{vulnerabilities};
|
my $vulnerabilities = $json_pretty->{scanResult}->[0]->{vulnerabilities};
|
||||||
foreach my $f ( @$vulnerabilities ) {
|
foreach my $f ( @$vulnerabilities ) {
|
||||||
@ -50,4 +52,4 @@ sub json($) {
|
|||||||
$file = `cat $file`;
|
$file = `cat $file`;
|
||||||
unlink $file;
|
unlink $file;
|
||||||
return from_json($file);
|
return from_json($file);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ my (
|
|||||||
pass("Running testssl.sh against ssl.sectionzero.org"); $tests++;
|
pass("Running testssl.sh against ssl.sectionzero.org"); $tests++;
|
||||||
$out = `./testssl.sh -H --jsonfile tmp.json --color 0 ssl.sectionzero.org`;
|
$out = `./testssl.sh -H --jsonfile tmp.json --color 0 ssl.sectionzero.org`;
|
||||||
$json = json('tmp.json');
|
$json = json('tmp.json');
|
||||||
|
unlink 'tmp.json';
|
||||||
|
|
||||||
# It is better to have findings in a hash
|
# It is better to have findings in a hash
|
||||||
# Look for a host cert match in the process.
|
# Look for a host cert match in the process.
|
||||||
|
496
testssl.sh
496
testssl.sh
@ -186,6 +186,7 @@ GIVE_HINTS=false # give an addtional info to findings
|
|||||||
HAS_IPv6=${HAS_IPv6:-false} # if you have OpenSSL with IPv6 support AND IPv6 networking set it to yes
|
HAS_IPv6=${HAS_IPv6:-false} # if you have OpenSSL with IPv6 support AND IPv6 networking set it to yes
|
||||||
UNBRACKTD_IPV6=${UNBRACKTD_IPV6:-false} # some versions of OpenSSL (like Gentoo) don't support [bracketed] IPv6 addresses
|
UNBRACKTD_IPV6=${UNBRACKTD_IPV6:-false} # some versions of OpenSSL (like Gentoo) don't support [bracketed] IPv6 addresses
|
||||||
SERVER_SIZE_LIMIT_BUG=false # Some servers have either a ClientHello total size limit or a 128 cipher limit (e.g. old ASAs)
|
SERVER_SIZE_LIMIT_BUG=false # Some servers have either a ClientHello total size limit or a 128 cipher limit (e.g. old ASAs)
|
||||||
|
CHILD_MASS_TESTING=${CHILD_MASS_TESTING:-false}
|
||||||
|
|
||||||
# tuning vars, can not be set by a cmd line switch
|
# tuning vars, can not be set by a cmd line switch
|
||||||
EXPERIMENTAL=${EXPERIMENTAL:-false}
|
EXPERIMENTAL=${EXPERIMENTAL:-false}
|
||||||
@ -741,7 +742,7 @@ pr_url() { tm_out "$1"; html_out "<a href="$1" style=\"color:black;text-deco
|
|||||||
pr_boldurl() { tm_bold "$1"; html_out "<a href="$1" style=\"font-weight:bold;color:black;text-decoration:none;\">$1</a>"; }
|
pr_boldurl() { tm_bold "$1"; html_out "<a href="$1" style=\"font-weight:bold;color:black;text-decoration:none;\">$1</a>"; }
|
||||||
|
|
||||||
### color switcher (see e.g. https://linuxtidbits.wordpress.com/2008/08/11/output-color-on-bash-scripts/
|
### color switcher (see e.g. https://linuxtidbits.wordpress.com/2008/08/11/output-color-on-bash-scripts/
|
||||||
### http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html
|
### http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html
|
||||||
set_color_functions() {
|
set_color_functions() {
|
||||||
local ncurses_tput=true
|
local ncurses_tput=true
|
||||||
|
|
||||||
@ -844,7 +845,7 @@ fileout_section_header() {
|
|||||||
"$do_pretty_json" && FIRST_FINDING=true && (printf "%s%s\n" "$str" "$(fileout_json_section "$1")") >> "$JSONFILE"
|
"$do_pretty_json" && FIRST_FINDING=true && (printf "%s%s\n" "$str" "$(fileout_json_section "$1")") >> "$JSONFILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
fileout_section_footer() {
|
fileout_section_footer() {
|
||||||
"$do_pretty_json" && printf "\n ]" >> "$JSONFILE"
|
"$do_pretty_json" && printf "\n ]" >> "$JSONFILE"
|
||||||
"$do_pretty_json" && "$1" && echo -e "\n }" >> "$JSONFILE"
|
"$do_pretty_json" && "$1" && echo -e "\n }" >> "$JSONFILE"
|
||||||
}
|
}
|
||||||
@ -866,6 +867,8 @@ fileout_json_print_parameter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileout_json_finding() {
|
fileout_json_finding() {
|
||||||
|
local target
|
||||||
|
|
||||||
if "$do_json"; then
|
if "$do_json"; then
|
||||||
"$FIRST_FINDING" || echo -n "," >> "$JSONFILE"
|
"$FIRST_FINDING" || echo -n "," >> "$JSONFILE"
|
||||||
echo -e " {" >> "$JSONFILE"
|
echo -e " {" >> "$JSONFILE"
|
||||||
@ -884,9 +887,19 @@ fileout_json_finding() {
|
|||||||
if [[ $SERVER_COUNTER -gt 1 ]]; then
|
if [[ $SERVER_COUNTER -gt 1 ]]; then
|
||||||
echo " ," >> "$JSONFILE"
|
echo " ," >> "$JSONFILE"
|
||||||
fi
|
fi
|
||||||
echo -e " {
|
if "$CHILD_MASS_TESTING" && ! "$JSONHEADER"; then
|
||||||
|
target="$NODE"
|
||||||
|
$do_mx_all_ips && target="$URI"
|
||||||
|
echo -e " {
|
||||||
|
\"target host\" : \"$target\",
|
||||||
|
\"port\" : \"$PORT\",
|
||||||
\"service\" : \"$finding\",
|
\"service\" : \"$finding\",
|
||||||
\"ip\" : \"$NODEIP\"," >> "$JSONFILE"
|
\"ip\" : \"$NODEIP\"," >> "$JSONFILE"
|
||||||
|
else
|
||||||
|
echo -e " {
|
||||||
|
\"service\" : \"$finding\",
|
||||||
|
\"ip\" : \"$NODEIP\"," >> "$JSONFILE"
|
||||||
|
fi
|
||||||
$do_mx_all_ips && echo -e " \"hostname\" : \"$NODE\"," >> "$JSONFILE"
|
$do_mx_all_ips && echo -e " \"hostname\" : \"$NODE\"," >> "$JSONFILE"
|
||||||
else
|
else
|
||||||
("$FIRST_FINDING" && echo -n " {" >> "$JSONFILE") || echo -n ",{" >> "$JSONFILE"
|
("$FIRST_FINDING" && echo -n " {" >> "$JSONFILE") || echo -n ",{" >> "$JSONFILE"
|
||||||
@ -905,7 +918,22 @@ fileout_json_finding() {
|
|||||||
##################### FILE FORMATING #########################
|
##################### FILE FORMATING #########################
|
||||||
|
|
||||||
fileout_pretty_json_banner() {
|
fileout_pretty_json_banner() {
|
||||||
echo -e " \"Invocation\" : \"$PROG_NAME $CMDLINE\",
|
local target
|
||||||
|
|
||||||
|
if "$do_mass_testing"; then
|
||||||
|
echo -e " \"Invocation\" : \"$PROG_NAME $CMDLINE\",
|
||||||
|
\"at\" : \"$HNAME:$OPENSSL_LOCATION\",
|
||||||
|
\"version\" : \"$VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE\",
|
||||||
|
\"openssl\" : \"$OSSL_VER from $OSSL_BUILD_DATE\",
|
||||||
|
\"startTime\" : \"$START_TIME\",
|
||||||
|
\"scanResult\" : ["
|
||||||
|
else
|
||||||
|
[[ -z "$NODE" ]] && parse_hn_port "${URI}"
|
||||||
|
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
||||||
|
target="$NODE"
|
||||||
|
$do_mx_all_ips && target="$URI"
|
||||||
|
|
||||||
|
echo -e " \"Invocation\" : \"$PROG_NAME $CMDLINE\",
|
||||||
\"at\" : \"$HNAME:$OPENSSL_LOCATION\",
|
\"at\" : \"$HNAME:$OPENSSL_LOCATION\",
|
||||||
\"version\" : \"$VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE\",
|
\"version\" : \"$VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE\",
|
||||||
\"openssl\" : \"$OSSL_VER from $OSSL_BUILD_DATE\",
|
\"openssl\" : \"$OSSL_VER from $OSSL_BUILD_DATE\",
|
||||||
@ -913,12 +941,10 @@ fileout_pretty_json_banner() {
|
|||||||
\"port\" : \"$PORT\",
|
\"port\" : \"$PORT\",
|
||||||
\"startTime\" : \"$START_TIME\",
|
\"startTime\" : \"$START_TIME\",
|
||||||
\"scanResult\" : ["
|
\"scanResult\" : ["
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
fileout_banner() {
|
fileout_banner() {
|
||||||
local target="$NODE"
|
|
||||||
$do_mx_all_ips && target="$URI"
|
|
||||||
|
|
||||||
#if ! "$APPEND"; then
|
#if ! "$APPEND"; then
|
||||||
# if "$CSVHEADER"; then
|
# if "$CSVHEADER"; then
|
||||||
# :
|
# :
|
||||||
@ -930,6 +956,13 @@ fileout_banner() {
|
|||||||
#fi
|
#fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileout_separator() {
|
||||||
|
if "$JSONHEADER"; then
|
||||||
|
"$do_pretty_json" && echo " ," >> "$JSONFILE"
|
||||||
|
"$do_json" && echo -n "," >> "$JSONFILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
fileout_footer() {
|
fileout_footer() {
|
||||||
if "$JSONHEADER"; then
|
if "$JSONHEADER"; then
|
||||||
fileout_json_footer
|
fileout_json_footer
|
||||||
@ -956,18 +989,18 @@ fileout() {
|
|||||||
|
|
||||||
json_header() {
|
json_header() {
|
||||||
local fname_prefix
|
local fname_prefix
|
||||||
|
local filename_provided=false
|
||||||
|
|
||||||
|
[[ -n "$JSONFILE" ]] && [[ ! -d "$JSONFILE" ]] && filename_provided=true
|
||||||
|
|
||||||
# Similar to HTML: Don't create headers and footers in the following scenarios:
|
# Similar to HTML: Don't create headers and footers in the following scenarios:
|
||||||
# * no JSON/CSV output is being created.
|
# * no JSON/CSV output is being created.
|
||||||
# * mass testing is being performed and each test will have its own file.
|
# * mass testing is being performed and each test will have its own file.
|
||||||
# * this is an individual test within a mass test and all output is being placed in a single file.
|
# * this is an individual test within a mass test and all output is being placed in a single file.
|
||||||
|
! "$do_json" && ! "$do_pretty_json" && JSONHEADER=false && return 0
|
||||||
|
"$do_mass_testing" && ! "$filename_provided" && JSONHEADER=false && return 0
|
||||||
|
"$CHILD_MASS_TESTING" && "$filename_provided" && JSONHEADER=false && return 0
|
||||||
|
|
||||||
if ( ! "$do_json" && ! "$do_pretty_json" ) || \
|
|
||||||
( "$do_mass_testing" && ( [[ -z "$JSONFILE" ]] || [[ -d "$JSONFILE" ]] ) ) || \
|
|
||||||
( "$APPEND" && [[ -n "$JSONFILE" ]] && [[ ! -d "$JSONFILE" ]] ); then
|
|
||||||
JSONHEADER=false
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if "$do_display_only"; then
|
if "$do_display_only"; then
|
||||||
fname_prefix="local-ciphers"
|
fname_prefix="local-ciphers"
|
||||||
elif "$do_mass_testing"; then
|
elif "$do_mass_testing"; then
|
||||||
@ -975,19 +1008,22 @@ json_header() {
|
|||||||
elif "$do_mx_all_ips"; then
|
elif "$do_mx_all_ips"; then
|
||||||
fname_prefix="mx-$URI"
|
fname_prefix="mx-$URI"
|
||||||
else
|
else
|
||||||
( [[ -z "$JSONFILE" ]] || [[ -d "$JSONFILE" ]] ) && parse_hn_port "${URI}"
|
! "$filename_provided" && [[ -z "$NODE" ]] && parse_hn_port "${URI}"
|
||||||
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
||||||
fname_prefix="${NODE}"_p"${PORT}"
|
fname_prefix="${NODE}"_p"${PORT}"
|
||||||
fi
|
fi
|
||||||
if [[ -n "$JSONFILE" ]] && [[ ! -d "$JSONFILE" ]]; then
|
if [[ -z "$JSONFILE" ]]; then
|
||||||
rm -f "$JSONFILE"
|
|
||||||
elif [[ -z "$JSONFILE" ]]; then
|
|
||||||
JSONFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
JSONFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
||||||
else
|
elif [[ -d "$JSONFILE" ]]; then
|
||||||
JSONFILE=$JSONFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
JSONFILE=$JSONFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
||||||
fi
|
fi
|
||||||
"$do_json" && printf "[\n" > "$JSONFILE"
|
if "$APPEND"; then
|
||||||
"$do_pretty_json" && printf "{\n" > "$JSONFILE"
|
JSONHEADER=false
|
||||||
|
else
|
||||||
|
[[ -e "$JSONFILE" ]] && fatal "\"$JSONFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||||
|
"$do_json" && printf "[\n" > "$JSONFILE"
|
||||||
|
"$do_pretty_json" && printf "{\n" > "$JSONFILE"
|
||||||
|
fi
|
||||||
#FIRST_FINDING=false
|
#FIRST_FINDING=false
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -995,14 +1031,15 @@ json_header() {
|
|||||||
|
|
||||||
csv_header() {
|
csv_header() {
|
||||||
local fname_prefix
|
local fname_prefix
|
||||||
|
local filename_provided=false
|
||||||
|
|
||||||
|
[[ -n "$CSVFILE" ]] && [[ ! -d "$CSVFILE" ]] && filename_provided=true
|
||||||
|
|
||||||
# CSV similar:
|
# CSV similar:
|
||||||
if ! "$do_csv" || \
|
! "$do_csv" && CSVHEADER=false && return 0
|
||||||
( "$do_mass_testing" && ( [[ -z "$CSVFILE" ]] || [[ -d "$CSVFILE" ]] ) ) || \
|
"$do_mass_testing" && ! "$filename_provided" && CSVHEADER=false && return 0
|
||||||
( "$APPEND" && [[ -n "$CSVFILE" ]] && [[ ! -d "$CSVFILE" ]] ); then
|
"$CHILD_MASS_TESTING" && "$filename_provided" && CSVHEADER=false && return 0
|
||||||
CSVHEADER=false
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if "$do_display_only"; then
|
if "$do_display_only"; then
|
||||||
fname_prefix="local-ciphers"
|
fname_prefix="local-ciphers"
|
||||||
elif "$do_mass_testing"; then
|
elif "$do_mass_testing"; then
|
||||||
@ -1010,18 +1047,22 @@ csv_header() {
|
|||||||
elif "$do_mx_all_ips"; then
|
elif "$do_mx_all_ips"; then
|
||||||
fname_prefix="mx-$URI"
|
fname_prefix="mx-$URI"
|
||||||
else
|
else
|
||||||
( [[ -z "$CSVFILE" ]] || [[ -d "$CSVFILE" ]] ) && parse_hn_port "${URI}"
|
! "$filename_provided" && [[ -z "$NODE" ]] && parse_hn_port "${URI}"
|
||||||
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
||||||
fname_prefix="${NODE}"_p"${PORT}"
|
fname_prefix="${NODE}"_p"${PORT}"
|
||||||
fi
|
fi
|
||||||
if [[ -n "$CSVFILE" ]] && [[ ! -d "$CSVFILE" ]]; then
|
|
||||||
rm -f "$CSVFILE"
|
if [[ -z "$CSVFILE" ]]; then
|
||||||
elif [[ -z "$CSVFILE" ]]; then
|
|
||||||
CSVFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
CSVFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
||||||
else
|
elif [[ -d "$CSVFILE" ]]; then
|
||||||
CSVFILE=$CSVFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
CSVFILE=$CSVFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
||||||
fi
|
fi
|
||||||
"$do_csv" && echo "\"id\",\"fqdn/ip\",\"port\",\"severity\",\"finding\",\"cve\",\"cwe\",\"hint\"" > "$CSVFILE"
|
if "$APPEND"; then
|
||||||
|
CSVHEADER=false
|
||||||
|
else
|
||||||
|
[[ -e "$CSVFILE" ]] && fatal "\"$CSVFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||||
|
echo "\"id\",\"fqdn/ip\",\"port\",\"severity\",\"finding\",\"cve\",\"cwe\",\"hint\"" > "$CSVFILE"
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1030,17 +1071,17 @@ csv_header() {
|
|||||||
|
|
||||||
html_header() {
|
html_header() {
|
||||||
local fname_prefix
|
local fname_prefix
|
||||||
|
local filename_provided=false
|
||||||
|
|
||||||
|
[[ -n "$HTMLFILE" ]] && [[ ! -d "$HTMLFILE" ]] && filename_provided=true
|
||||||
|
|
||||||
# Don't create HTML headers and footers in the following scenarios:
|
# Don't create HTML headers and footers in the following scenarios:
|
||||||
# * HTML output is not being created.
|
# * HTML output is not being created.
|
||||||
# * mass testing is being performed and each test will have its own HTML file.
|
# * mass testing is being performed and each test will have its own HTML file.
|
||||||
# * this is an individual test within a mass test and all HTML output is being placed in a single file.
|
# * this is an individual test within a mass test and all HTML output is being placed in a single file.
|
||||||
if ! "$do_html" || \
|
! "$do_html" && HTMLHEADER=false && return 0
|
||||||
( "$do_mass_testing" && ( [[ -z "$HTMLFILE" ]] || [[ -d "$HTMLFILE" ]] ) ) || \
|
"$do_mass_testing" && ! "$filename_provided" && HTMLHEADER=false && return 0
|
||||||
( "$APPEND" && [[ -n "$HTMLFILE" ]] && [[ ! -d "$HTMLFILE" ]] ); then
|
"$CHILD_MASS_TESTING" && "$filename_provided" && HTMLHEADER=false && return 0
|
||||||
HTMLHEADER=false
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if "$do_display_only"; then
|
if "$do_display_only"; then
|
||||||
fname_prefix="local-ciphers"
|
fname_prefix="local-ciphers"
|
||||||
@ -1049,33 +1090,36 @@ html_header() {
|
|||||||
elif "$do_mx_all_ips"; then
|
elif "$do_mx_all_ips"; then
|
||||||
fname_prefix="mx-$URI"
|
fname_prefix="mx-$URI"
|
||||||
else
|
else
|
||||||
( [[ -z "$HTMLFILE" ]] || [[ -d "$HTMLFILE" ]] ) && parse_hn_port "${URI}"
|
! "$filename_provided" && [[ -z "$NODE" ]] && parse_hn_port "${URI}"
|
||||||
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
||||||
fname_prefix="${NODE}"_p"${PORT}"
|
fname_prefix="${NODE}"_p"${PORT}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$HTMLFILE" ]] && [[ ! -d "$HTMLFILE" ]]; then
|
if [[ -z "$HTMLFILE" ]]; then
|
||||||
rm -f "$HTMLFILE"
|
|
||||||
elif [[ -z "$HTMLFILE" ]]; then
|
|
||||||
HTMLFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".html)
|
HTMLFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".html)
|
||||||
else
|
elif [[ -d "$HTMLFILE" ]]; then
|
||||||
HTMLFILE=$HTMLFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".html)
|
HTMLFILE=$HTMLFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".html)
|
||||||
fi
|
fi
|
||||||
html_out "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
if "$APPEND"; then
|
||||||
html_out "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
|
HTMLHEADER=false
|
||||||
html_out "<!-- This file was created with testssl.sh. https://testssl.sh -->\n"
|
else
|
||||||
html_out "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
|
[[ -e "$HTMLFILE" ]] && fatal "\"$HTMLFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||||
html_out "<head>\n"
|
html_out "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
||||||
html_out "<meta http-equiv=\"Content-Type\" content=\"application/xml+xhtml; charset=UTF-8\" />\n"
|
html_out "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
|
||||||
html_out "<title>testssl.sh</title>\n"
|
html_out "<!-- This file was created with testssl.sh. https://testssl.sh -->\n"
|
||||||
html_out "</head>\n"
|
html_out "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
|
||||||
html_out "<body>\n"
|
html_out "<head>\n"
|
||||||
html_out "<pre>\n"
|
html_out "<meta http-equiv=\"Content-Type\" content=\"application/xml+xhtml; charset=UTF-8\" />\n"
|
||||||
|
html_out "<title>testssl.sh</title>\n"
|
||||||
|
html_out "</head>\n"
|
||||||
|
html_out "<body>\n"
|
||||||
|
html_out "<pre>\n"
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
html_banner() {
|
html_banner() {
|
||||||
if "$APPEND" && "$HTMLHEADER"; then
|
if "$CHILD_MASS_TESTING" && "$HTMLHEADER"; then
|
||||||
html_out "## Scan started as: \"$PROG_NAME $CMDLINE\"\n"
|
html_out "## Scan started as: \"$PROG_NAME $CMDLINE\"\n"
|
||||||
html_out "## at $HNAME:$OPENSSL_LOCATION\n"
|
html_out "## at $HNAME:$OPENSSL_LOCATION\n"
|
||||||
html_out "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE\n"
|
html_out "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE\n"
|
||||||
@ -1102,8 +1146,8 @@ if [[ $(uname) == "Linux" ]] ; then
|
|||||||
toupper() { echo -n "${1^^}" ; }
|
toupper() { echo -n "${1^^}" ; }
|
||||||
tolower() { echo -n "${1,,}" ; }
|
tolower() { echo -n "${1,,}" ; }
|
||||||
else
|
else
|
||||||
toupper() { echo -n "$1" | tr 'a-z' 'A-Z'; }
|
toupper() { tr 'a-z' 'A-Z' <<< "$1"; }
|
||||||
tolower() { echo -n "$1" | tr 'A-Z' 'a-z' ; }
|
tolower() { tr 'A-Z' 'a-z' <<< "$1"; }
|
||||||
fi
|
fi
|
||||||
|
|
||||||
debugme() {
|
debugme() {
|
||||||
@ -1137,7 +1181,7 @@ count_words() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count_ciphers() {
|
count_ciphers() {
|
||||||
echo -n "$1" | sed 's/:/ /g' | wc -w | sed 's/ //g'
|
echo $(wc -w <<< "${1//:/ }")
|
||||||
}
|
}
|
||||||
|
|
||||||
actually_supported_ciphers() {
|
actually_supported_ciphers() {
|
||||||
@ -1432,7 +1476,6 @@ service_detection() {
|
|||||||
head $TMPFILE | egrep -aqw "Jive News|InterNetNews|NNRP|INN" && SERVICE=NNTP
|
head $TMPFILE | egrep -aqw "Jive News|InterNetNews|NNRP|INN" && SERVICE=NNTP
|
||||||
debugme head -50 $TMPFILE
|
debugme head -50 $TMPFILE
|
||||||
fi
|
fi
|
||||||
# FIXME: we can guess ports by port number if not properly recognized (and label it as guessed)
|
|
||||||
|
|
||||||
out " Service detected: $CORRECT_SPACES"
|
out " Service detected: $CORRECT_SPACES"
|
||||||
case $SERVICE in
|
case $SERVICE in
|
||||||
@ -2450,7 +2493,7 @@ std_cipherlists() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
tmpfile_handle $FUNCNAME.$debugname.txt
|
tmpfile_handle $FUNCNAME.$debugname.txt
|
||||||
[[ $DEBUG -ge 1 ]] && outln " -- $1" || outln #FIXME: should be in standard output at some time
|
[[ $DEBUG -ge 1 ]] && tmln_out " -- $1" || tmln_out
|
||||||
else
|
else
|
||||||
singlespaces=$(sed -e 's/ \+/ /g' -e 's/^ //' -e 's/ $//g' -e 's/ //g' <<< "$2")
|
singlespaces=$(sed -e 's/ \+/ /g' -e 's/^ //' -e 's/ $//g' -e 's/ //g' <<< "$2")
|
||||||
if [[ "$OPTIMAL_PROTO" == "-ssl2" ]]; then
|
if [[ "$OPTIMAL_PROTO" == "-ssl2" ]]; then
|
||||||
@ -6080,18 +6123,16 @@ certificate_info() {
|
|||||||
|
|
||||||
|
|
||||||
run_server_defaults() {
|
run_server_defaults() {
|
||||||
local ciph match_found newhostcert sni
|
local ciph newhostcert sni
|
||||||
local sessticket_str=""
|
local match_found
|
||||||
local lifetime unit
|
local sessticket_str="" lifetime unit
|
||||||
local line
|
|
||||||
local -i i n
|
local -i i n
|
||||||
local -i certs_found=0
|
local -i certs_found=0
|
||||||
local -a previous_hostcert previous_intermediates keysize cipher
|
local -a previous_hostcert previous_intermediates keysize cipher
|
||||||
local -a ocsp_response ocsp_response_status sni_used
|
local -a ocsp_response ocsp_response_status sni_used
|
||||||
local -a ciphers_to_test success
|
local -a ciphers_to_test
|
||||||
|
local -a -i success
|
||||||
local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions
|
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
|
|
||||||
|
|
||||||
# Try each public key type once:
|
# Try each public key type once:
|
||||||
# ciphers_to_test[1]: cipher suites using certificates with RSA signature public keys
|
# ciphers_to_test[1]: cipher suites using certificates with RSA signature public keys
|
||||||
@ -6104,11 +6145,11 @@ run_server_defaults() {
|
|||||||
ciphers_to_test[1]=""
|
ciphers_to_test[1]=""
|
||||||
ciphers_to_test[2]=""
|
ciphers_to_test[2]=""
|
||||||
for ciph in $(colon_to_spaces $($OPENSSL ciphers "aRSA")); do
|
for ciph in $(colon_to_spaces $($OPENSSL ciphers "aRSA")); do
|
||||||
if grep -q "\-RSA\-" <<<$ciph; then
|
if grep -q "\-RSA\-" <<<$ciph; then
|
||||||
ciphers_to_test[1]="${ciphers_to_test[1]}:$ciph"
|
ciphers_to_test[1]="${ciphers_to_test[1]}:$ciph"
|
||||||
else
|
else
|
||||||
ciphers_to_test[2]="${ciphers_to_test[2]}:$ciph"
|
ciphers_to_test[2]="${ciphers_to_test[2]}:$ciph"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
[[ -n "${ciphers_to_test[1]}" ]] && ciphers_to_test[1]="${ciphers_to_test[1]:1}"
|
[[ -n "${ciphers_to_test[1]}" ]] && ciphers_to_test[1]="${ciphers_to_test[1]:1}"
|
||||||
[[ -n "${ciphers_to_test[2]}" ]] && ciphers_to_test[2]="${ciphers_to_test[2]:1}"
|
[[ -n "${ciphers_to_test[2]}" ]] && ciphers_to_test[2]="${ciphers_to_test[2]:1}"
|
||||||
@ -6119,94 +6160,96 @@ run_server_defaults() {
|
|||||||
ciphers_to_test[7]="aGOST"
|
ciphers_to_test[7]="aGOST"
|
||||||
|
|
||||||
for (( n=1; n <= 14 ; n++ )); do
|
for (( n=1; n <= 14 ; n++ )); do
|
||||||
# Some servers use a different certificate if the ClientHello
|
# Some servers use a different certificate if the ClientHello
|
||||||
# specifies TLSv1.1 and doesn't include a server name extension.
|
# specifies TLSv1.1 and doesn't include a server name extension.
|
||||||
# So, for each public key type for which a certificate was found,
|
# So, for each public key type for which a certificate was found,
|
||||||
# try again, but only with TLSv1.1 and without SNI.
|
# try again, but only with TLSv1.1 and without SNI.
|
||||||
if [[ $n -ge 8 ]]; then
|
if [[ $n -ge 8 ]]; then
|
||||||
ciphers_to_test[n]=""
|
ciphers_to_test[n]=""
|
||||||
[[ ${success[n-7]} -eq 0 ]] && ciphers_to_test[n]="${ciphers_to_test[n-7]}"
|
[[ ${success[n-7]} -eq 0 ]] && ciphers_to_test[n]="${ciphers_to_test[n-7]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${ciphers_to_test[n]}" ]] && [[ $(count_ciphers $($OPENSSL ciphers "${ciphers_to_test[n]}" 2>>$ERRFILE)) -ge 1 ]]; then
|
if [[ -n "${ciphers_to_test[n]}" ]] && [[ $(count_ciphers $($OPENSSL ciphers "${ciphers_to_test[n]}" 2>>$ERRFILE)) -ge 1 ]]; then
|
||||||
if [[ $n -ge 8 ]]; then
|
if [[ $n -ge 8 ]]; then
|
||||||
sni="$SNI"
|
sni="$SNI"
|
||||||
SNI=""
|
SNI=""
|
||||||
get_server_certificate "-cipher ${ciphers_to_test[n]}" "tls1_1"
|
get_server_certificate "-cipher ${ciphers_to_test[n]}" "tls1_1"
|
||||||
success[n]=$?
|
success[n]=$?
|
||||||
SNI="$sni"
|
SNI="$sni"
|
||||||
else
|
else
|
||||||
get_server_certificate "-cipher ${ciphers_to_test[n]}"
|
get_server_certificate "-cipher ${ciphers_to_test[n]}"
|
||||||
success[n]=$?
|
success[n]=$?
|
||||||
fi
|
fi
|
||||||
if [[ ${success[n]} -eq 0 ]]; then
|
if [[ ${success[n]} -eq 0 ]]; then
|
||||||
cp "$TEMPDIR/$NODEIP.get_server_certificate.txt" $TMPFILE
|
cp "$TEMPDIR/$NODEIP.get_server_certificate.txt" $TMPFILE
|
||||||
>$ERRFILE
|
>$ERRFILE
|
||||||
if [[ -z "$sessticket_str" ]]; then
|
if [[ -z "$sessticket_str" ]]; then
|
||||||
sessticket_str=$(grep -aw "session ticket" $TMPFILE | grep -a lifetime)
|
sessticket_str=$(grep -aw "session ticket" $TMPFILE | grep -a lifetime)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# check whether the host's certificate has been seen before
|
# check whether the host's certificate has been seen before
|
||||||
match_found=false
|
match_found=false
|
||||||
i=1
|
i=1
|
||||||
newhostcert=$(cat $HOSTCERT)
|
newhostcert=$(cat $HOSTCERT)
|
||||||
while [[ $i -le $certs_found ]]; do
|
while [[ $i -le $certs_found ]]; do
|
||||||
if [[ "$newhostcert" == "${previous_hostcert[i]}" ]]; then
|
if [[ "$newhostcert" == "${previous_hostcert[i]}" ]]; then
|
||||||
match_found=true
|
match_found=true
|
||||||
break;
|
break;
|
||||||
fi
|
fi
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
done
|
done
|
||||||
if ! "$match_found" && [[ $n -ge 8 ]] && [[ $certs_found -ne 0 ]]; then
|
if ! "$match_found" && [[ $n -ge 8 ]] && [[ $certs_found -ne 0 ]]; then
|
||||||
# A new certificate was found using TLSv1.1 without SNI.
|
# A new certificate was found using TLSv1.1 without SNI.
|
||||||
# Check to see if the new certificate should be displayed.
|
# Check to see if the new certificate should be displayed.
|
||||||
# It should be displayed if it is either a match for the
|
# It should be displayed if it is either a match for the
|
||||||
# $NODE being tested or if it has the same subject
|
# $NODE being tested or if it has the same subject
|
||||||
# (CN and SAN) as other certificates for this host.
|
# (CN and SAN) as other certificates for this host.
|
||||||
compare_server_name_to_cert "$NODE" "$HOSTCERT"
|
compare_server_name_to_cert "$NODE" "$HOSTCERT"
|
||||||
[[ $? -ne 0 ]] && success[n]=0 || success[n]=1
|
[[ $? -ne 0 ]] && success[n]=0 || success[n]=1
|
||||||
|
|
||||||
if [[ ${success[n]} -ne 0 ]]; then
|
if [[ ${success[n]} -ne 0 ]]; then
|
||||||
cn_nosni="$(toupper "$(get_cn_from_cert $HOSTCERT)")"
|
cn_nosni="$(toupper "$(get_cn_from_cert $HOSTCERT)")"
|
||||||
sans_nosni="$(toupper "$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \
|
sans_nosni="$(toupper "$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | \
|
||||||
tr ',' '\n' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g' | tr '\n' ' ')")"
|
grep -A2 "Subject Alternative Name" | tr ',' '\n' | grep "DNS:" | \
|
||||||
|
sed -e 's/DNS://g' -e 's/ //g' | tr '\n' ' ')")"
|
||||||
|
|
||||||
echo "${previous_hostcert[1]}" > $HOSTCERT
|
echo "${previous_hostcert[1]}" > $HOSTCERT
|
||||||
cn_sni="$(toupper "$(get_cn_from_cert $HOSTCERT)")"
|
cn_sni="$(toupper "$(get_cn_from_cert $HOSTCERT)")"
|
||||||
|
|
||||||
# FIXME: Not sure what the matching rule should be. At
|
# FIXME: Not sure what the matching rule should be. At
|
||||||
# the moment, the no SNI certificate is considered a
|
# the moment, the no SNI certificate is considered a
|
||||||
# match if the CNs are the same and the SANs (if
|
# match if the CNs are the same and the SANs (if
|
||||||
# present) contain at least one DNS name in common.
|
# present) contain at least one DNS name in common.
|
||||||
if [[ "$cn_nosni" == "$cn_sni" ]]; then
|
if [[ "$cn_nosni" == "$cn_sni" ]]; then
|
||||||
sans_sni="$(toupper "$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \
|
sans_sni="$(toupper "$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | \
|
||||||
tr ',' '\n' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g' | tr '\n' ' ')")"
|
grep -A2 "Subject Alternative Name" | tr ',' '\n' | grep "DNS:" | \
|
||||||
if [[ "$sans_nosni" == "$sans_sni" ]]; then
|
sed -e 's/DNS://g' -e 's/ //g' | tr '\n' ' ')")"
|
||||||
success[n]=0
|
if [[ "$sans_nosni" == "$sans_sni" ]]; then
|
||||||
else
|
success[n]=0
|
||||||
for san in $sans_nosni; do
|
else
|
||||||
[[ " $sans_sni " =~ " $san " ]] && success[n]=0 && break
|
for san in $sans_nosni; do
|
||||||
done
|
[[ " $sans_sni " =~ " $san " ]] && success[n]=0 && break
|
||||||
|
done
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
# If the certificate found for TLSv1.1 w/o SNI appears to
|
||||||
# If the certificate found for TLSv1.1 w/o SNI appears to
|
# be for a different host, then set match_found to true so
|
||||||
# be for a different host, then set match_found to true so
|
# that the new certificate will not be included in the output.
|
||||||
# that the new certificate will not be included in the output.
|
[[ ${success[n]} -ne 0 ]] && match_found=true
|
||||||
[[ ${success[n]} -ne 0 ]] && match_found=true
|
fi
|
||||||
fi
|
if ! "$match_found"; then
|
||||||
if ! "$match_found"; then
|
certs_found=$(($certs_found + 1))
|
||||||
certs_found=$(($certs_found + 1))
|
cipher[certs_found]=${ciphers_to_test[n]}
|
||||||
cipher[certs_found]=${ciphers_to_test[n]}
|
keysize[certs_found]=$(grep -aw "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //' -e 's/bit//' -e 's/ //')
|
||||||
keysize[certs_found]=$(grep -aw "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //' -e 's/bit//' -e 's/ //')
|
ocsp_response[certs_found]=$(grep -aA 20 "OCSP response" $TMPFILE)
|
||||||
ocsp_response[certs_found]=$(grep -aA 20 "OCSP response" $TMPFILE)
|
ocsp_response_status[certs_found]=$(grep -a "OCSP Response Status" $TMPFILE)
|
||||||
ocsp_response_status[certs_found]=$(grep -a "OCSP Response Status" $TMPFILE)
|
previous_hostcert[certs_found]=$newhostcert
|
||||||
previous_hostcert[certs_found]=$newhostcert
|
previous_intermediates[certs_found]=$(cat $TEMPDIR/intermediatecerts.pem)
|
||||||
previous_intermediates[certs_found]=$(cat $TEMPDIR/intermediatecerts.pem)
|
[[ $n -ge 8 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI"
|
||||||
[[ $n -ge 8 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI"
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
determine_tls_extensions
|
determine_tls_extensions
|
||||||
@ -6249,7 +6292,7 @@ run_server_defaults() {
|
|||||||
unit=$(grep -a lifetime <<< "$sessticket_str" | sed -e 's/^.*'"$lifetime"'//' -e 's/[ ()]//g')
|
unit=$(grep -a lifetime <<< "$sessticket_str" | sed -e 's/^.*'"$lifetime"'//' -e 's/[ ()]//g')
|
||||||
out "$lifetime $unit "
|
out "$lifetime $unit "
|
||||||
prln_svrty_low "(PFS requires session ticket keys to be rotated <= daily)"
|
prln_svrty_low "(PFS requires session ticket keys to be rotated <= daily)"
|
||||||
fileout "session_ticket" "LOW" "TLS session tickes RFC 5077 valid for $lifetime $unit (PFS requires session ticket keys to be rotated at least daily)"
|
fileout "session_ticket" "LOW" "TLS session ticket RFC 5077 valid for $lifetime $unit (PFS requires session ticket keys to be rotated at least daily)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pr_bold " SSL Session ID support "
|
pr_bold " SSL Session ID support "
|
||||||
@ -6265,10 +6308,10 @@ run_server_defaults() {
|
|||||||
|
|
||||||
i=1
|
i=1
|
||||||
while [[ $i -le $certs_found ]]; do
|
while [[ $i -le $certs_found ]]; do
|
||||||
echo "${previous_hostcert[i]}" > $HOSTCERT
|
echo "${previous_hostcert[i]}" > $HOSTCERT
|
||||||
echo "${previous_intermediates[i]}" > $TEMPDIR/intermediatecerts.pem
|
echo "${previous_intermediates[i]}" > $TEMPDIR/intermediatecerts.pem
|
||||||
certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}"
|
certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}"
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10111,7 +10154,7 @@ run_beast(){
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if ! "$vuln_beast" ; then
|
if ! "$vuln_beast" ; then
|
||||||
prln_done_good " no CBC ciphers for $(toupper $proto) (OK)"
|
prln_done_good "no CBC ciphers for $(toupper $proto) (OK)"
|
||||||
fileout "cbc_$proto" "OK" "BEAST: No CBC ciphers for $(toupper $proto)" "$cve" "$cwe"
|
fileout "cbc_$proto" "OK" "BEAST: No CBC ciphers for $(toupper $proto)" "$cve" "$cwe"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -10831,7 +10874,7 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
maketempf() {
|
maketempf() {
|
||||||
TEMPDIR=$(mktemp -d /tmp/ssltester.XXXXXX) || exit -6
|
TEMPDIR=$(mktemp -d /tmp/testssl.XXXXXX) || exit -6
|
||||||
TMPFILE=$TEMPDIR/tempfile.txt || exit -6
|
TMPFILE=$TEMPDIR/tempfile.txt || exit -6
|
||||||
if [[ "$DEBUG" -eq 0 ]]; then
|
if [[ "$DEBUG" -eq 0 ]]; then
|
||||||
ERRFILE="/dev/null"
|
ERRFILE="/dev/null"
|
||||||
@ -10957,7 +11000,8 @@ mybanner() {
|
|||||||
local idtag
|
local idtag
|
||||||
local bb1 bb2 bb3
|
local bb1 bb2 bb3
|
||||||
|
|
||||||
$QUIET && return
|
"$QUIET" && return
|
||||||
|
"$CHILD_MASS_TESTING" && return
|
||||||
OPENSSL_NR_CIPHERS=$(count_ciphers "$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>/dev/null)")
|
OPENSSL_NR_CIPHERS=$(count_ciphers "$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>/dev/null)")
|
||||||
[[ -z "$GIT_REL" ]] && \
|
[[ -z "$GIT_REL" ]] && \
|
||||||
idtag="$CVS_REL" || \
|
idtag="$CVS_REL" || \
|
||||||
@ -10965,7 +11009,7 @@ mybanner() {
|
|||||||
bb1=$(cat <<EOF
|
bb1=$(cat <<EOF
|
||||||
|
|
||||||
###########################################################
|
###########################################################
|
||||||
$PROG_NAME $VERSION from
|
$PROG_NAME $VERSION from
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
bb2=$(cat <<EOF
|
bb2=$(cat <<EOF
|
||||||
@ -10974,7 +11018,7 @@ EOF
|
|||||||
modification under GPLv2 permitted.
|
modification under GPLv2 permitted.
|
||||||
USAGE w/o ANY WARRANTY. USE IT AT YOUR OWN RISK!
|
USAGE w/o ANY WARRANTY. USE IT AT YOUR OWN RISK!
|
||||||
|
|
||||||
Please file bugs @
|
Please file bugs @
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
bb3=$(cat <<EOF
|
bb3=$(cat <<EOF
|
||||||
@ -11133,30 +11177,34 @@ parse_hn_port() {
|
|||||||
# arg1: for testing mx records name we put a name of logfile in here, otherwise we get strange file names
|
# arg1: for testing mx records name we put a name of logfile in here, otherwise we get strange file names
|
||||||
prepare_logging() {
|
prepare_logging() {
|
||||||
local fname_prefix="$1"
|
local fname_prefix="$1"
|
||||||
|
local filename_provided=false
|
||||||
|
|
||||||
|
[[ -n "$LOGFILE" ]] && [[ ! -d "$LOGFILE" ]] && filename_provided=true
|
||||||
|
|
||||||
|
# Similar to html_header():
|
||||||
|
! "$do_logging" && return 0
|
||||||
|
"$do_mass_testing" && ! "$filename_provided" && return 0
|
||||||
|
"$CHILD_MASS_TESTING" && "$filename_provided" && return 0
|
||||||
|
|
||||||
[[ -z "$fname_prefix" ]] && fname_prefix="${NODE}"_p"${PORT}"
|
[[ -z "$fname_prefix" ]] && fname_prefix="${NODE}"_p"${PORT}"
|
||||||
|
|
||||||
if "$do_logging"; then
|
if [[ -z "$LOGFILE" ]]; then
|
||||||
if [[ -z "$LOGFILE" ]]; then
|
LOGFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".log)
|
||||||
LOGFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".log)
|
elif [[ -d "$LOGFILE" ]]; then
|
||||||
elif [[ -d "$LOGFILE" ]]; then
|
# actually we were instructed to place all files in a DIR instead of the current working dir
|
||||||
# actually we were instructed to place all files in a DIR instead of the current working dir
|
LOGFILE=$LOGFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".log)
|
||||||
LOGFILE=$LOGFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".log)
|
else
|
||||||
else
|
: # just for clarity: a log file was specified, no need to do anything else
|
||||||
: # just for clarity: a log file was specified, no need to do anything else
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! "$APPEND"; then
|
|
||||||
[[ -e $LOGFILE ]] && fatal "\"$LOGFILE\" exists. Either use \"--append\" or (re)move it" 1
|
|
||||||
else
|
|
||||||
>$LOGFILE
|
|
||||||
fi
|
|
||||||
tmln_out "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>${LOGFILE}
|
|
||||||
tmln_out "## at $HNAME:$OPENSSL_LOCATION" >>${LOGFILE}
|
|
||||||
tmln_out "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>${LOGFILE}
|
|
||||||
tmln_out "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>${LOGFILE}
|
|
||||||
exec > >(tee -a ${LOGFILE})
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! "$APPEND"; then
|
||||||
|
[[ -e $LOGFILE ]] && fatal "\"$LOGFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||||
|
fi
|
||||||
|
tmln_out "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>${LOGFILE}
|
||||||
|
tmln_out "## at $HNAME:$OPENSSL_LOCATION" >>${LOGFILE}
|
||||||
|
tmln_out "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>${LOGFILE}
|
||||||
|
tmln_out "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>${LOGFILE}
|
||||||
|
exec > >(tee -a ${LOGFILE})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -11169,9 +11217,9 @@ filter_ip6_address() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
if "$HAS_SED_E"; then
|
if "$HAS_SED_E"; then
|
||||||
echo "$a" | sed -E 's/^abcdeABCDEFf0123456789:]//g' | sed -e '/^$/d' -e '/^;;/d'
|
sed -E 's/^abcdeABCDEFf0123456789:]//g' <<< "$a" | sed -e '/^$/d' -e '/^;;/d'
|
||||||
else
|
else
|
||||||
echo "$a" | sed -r 's/[^abcdefABCDEF0123456789:]//g' | sed -e '/^$/d' -e '/^;;/d'
|
sed -r 's/[^abcdefABCDEF0123456789:]//g' <<< "$a" | sed -e '/^$/d' -e '/^;;/d'
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@ -11184,9 +11232,9 @@ filter_ip4_address() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
if "$HAS_SED_E"; then
|
if "$HAS_SED_E"; then
|
||||||
echo "$a" | sed -E 's/[^[:digit:].]//g' | sed -e '/^$/d'
|
sed -E 's/[^[:digit:].]//g' <<< "$a" | sed -e '/^$/d'
|
||||||
else
|
else
|
||||||
echo "$a" | sed -r 's/[^[:digit:].]//g' | sed -e '/^$/d'
|
sed -r 's/[^[:digit:].]//g' <<< "$a" | sed -e '/^$/d'
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@ -11529,7 +11577,7 @@ sclient_auth() {
|
|||||||
# this function determines OPTIMAL_PROTO. It is a workaround function as under certain circumstances
|
# this function determines OPTIMAL_PROTO. It is a workaround function as under certain circumstances
|
||||||
# (e.g. IIS6.0 and openssl 1.0.2 as opposed to 1.0.1) needs a protocol otherwise s_client -connect will fail!
|
# (e.g. IIS6.0 and openssl 1.0.2 as opposed to 1.0.1) needs a protocol otherwise s_client -connect will fail!
|
||||||
# Circumstances observed so far: 1.) IIS 6 2.) starttls + dovecot imap
|
# Circumstances observed so far: 1.) IIS 6 2.) starttls + dovecot imap
|
||||||
# The first try in the loop is empty as we prefer not to specify always a protocol if it works w/o.
|
# The first try in the loop is empty as we prefer not to specify always a protocol if we can get along w/o it
|
||||||
#
|
#
|
||||||
determine_optimal_proto() {
|
determine_optimal_proto() {
|
||||||
local all_failed
|
local all_failed
|
||||||
@ -11610,9 +11658,9 @@ determine_service() {
|
|||||||
ua="$UA_SNEAKY" || \
|
ua="$UA_SNEAKY" || \
|
||||||
ua="$UA_STD"
|
ua="$UA_STD"
|
||||||
GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\nConnection: Close\r\nAccept: text/*\r\n\r\n"
|
GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\nConnection: Close\r\nAccept: text/*\r\n\r\n"
|
||||||
#HEAD_REQ11="HEAD $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\nAccept: text/*\r\n\r\n"
|
# HEAD_REQ11="HEAD $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\nAccept: text/*\r\n\r\n"
|
||||||
#GET_REQ10="GET $URL_PATH HTTP/1.0\r\nUser-Agent: $ua\r\nConnection: Close\r\nAccept: text/*\r\n\r\n"
|
# GET_REQ10="GET $URL_PATH HTTP/1.0\r\nUser-Agent: $ua\r\nConnection: Close\r\nAccept: text/*\r\n\r\n"
|
||||||
#HEAD_REQ10="HEAD $URL_PATH HTTP/1.0\r\nUser-Agent: $ua\r\nAccept: text/*\r\n\r\n"
|
# HEAD_REQ10="HEAD $URL_PATH HTTP/1.0\r\nUser-Agent: $ua\r\nAccept: text/*\r\n\r\n"
|
||||||
service_detection $OPTIMAL_PROTO
|
service_detection $OPTIMAL_PROTO
|
||||||
else
|
else
|
||||||
# STARTTLS
|
# STARTTLS
|
||||||
@ -11762,9 +11810,35 @@ run_mx_all_ips() {
|
|||||||
return $ret
|
return $ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run_mass_testing() {
|
||||||
|
local cmdline=""
|
||||||
|
local first=true
|
||||||
|
local global_cmdline=${CMDLINE%%--file*} # $global_cmdline may have arguments in addition to the one in the file
|
||||||
|
|
||||||
|
if [[ ! -r "$FNAME" ]] && "$IKNOW_FNAME"; then
|
||||||
|
fatal "Can't read file \"$FNAME\"" "2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pr_reverse "====== Running in file batch mode with file=\"$FNAME\" ======"; outln "\n"
|
||||||
|
while read cmdline; do
|
||||||
|
cmdline=$(filter_input "$cmdline")
|
||||||
|
[[ -z "$cmdline" ]] && continue
|
||||||
|
[[ "$cmdline" == "EOF" ]] && break
|
||||||
|
cmdline="$0 $global_cmdline --warnings=batch $cmdline"
|
||||||
|
draw_line "=" $((TERM_WIDTH / 2)); outln;
|
||||||
|
outln "$cmdline"
|
||||||
|
"$first" || fileout_separator # this is needed for appended output, see #687
|
||||||
|
CHILD_MASS_TESTING=true $cmdline # we call ourselves here. $do_mass_testing is the parent, $CHILD_MASS_TESTING... you figured
|
||||||
|
first=false
|
||||||
|
done < "${FNAME}"
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#FIXME: not called/tested yet
|
||||||
run_mass_testing_parallel() {
|
run_mass_testing_parallel() {
|
||||||
local cmdline=""
|
local cmdline=""
|
||||||
|
local first=true
|
||||||
local global_cmdline=${CMDLINE%%--file*}
|
local global_cmdline=${CMDLINE%%--file*}
|
||||||
|
|
||||||
if [[ ! -r "$FNAME" ]] && $IKNOW_FNAME; then
|
if [[ ! -r "$FNAME" ]] && $IKNOW_FNAME; then
|
||||||
@ -11777,40 +11851,17 @@ run_mass_testing_parallel() {
|
|||||||
cmdline=$(filter_input "$cmdline")
|
cmdline=$(filter_input "$cmdline")
|
||||||
[[ -z "$cmdline" ]] && continue
|
[[ -z "$cmdline" ]] && continue
|
||||||
[[ "$cmdline" == "EOF" ]] && break
|
[[ "$cmdline" == "EOF" ]] && break
|
||||||
cmdline="$0 $global_cmdline --warnings=batch -q $cmdline"
|
cmdline="$0 $global_cmdline --warnings=batch $cmdline"
|
||||||
draw_line "=" $((TERM_WIDTH / 2)); outln;
|
draw_line "=" $((TERM_WIDTH / 2)); outln;
|
||||||
determine_logfile
|
|
||||||
outln "$cmdline"
|
outln "$cmdline"
|
||||||
$cmdline >$LOGFILE &
|
CHILD_MASS_TESTING=true $cmdline >$LOGFILE &
|
||||||
|
# first=false
|
||||||
sleep $PARALLEL_SLEEP
|
sleep $PARALLEL_SLEEP
|
||||||
done < "$FNAME"
|
done < "$FNAME"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
run_mass_testing() {
|
|
||||||
local cmdline=""
|
|
||||||
local global_cmdline=${CMDLINE%%--file*}
|
|
||||||
|
|
||||||
if [[ ! -r "$FNAME" ]] && "$IKNOW_FNAME"; then
|
|
||||||
fatal "Can't read file \"$FNAME\"" "2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
pr_reverse "====== Running in file batch mode with file=\"$FNAME\" ======"; outln "\n"
|
|
||||||
APPEND=false # Make sure we close out our files
|
|
||||||
while read cmdline; do
|
|
||||||
cmdline=$(filter_input "$cmdline")
|
|
||||||
[[ -z "$cmdline" ]] && continue
|
|
||||||
[[ "$cmdline" == "EOF" ]] && break
|
|
||||||
cmdline="$0 $global_cmdline --warnings=batch -q --append $cmdline"
|
|
||||||
draw_line "=" $((TERM_WIDTH / 2)); outln;
|
|
||||||
outln "$cmdline"
|
|
||||||
$cmdline
|
|
||||||
done < "${FNAME}"
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# This initializes boolean global do_* variables. They keep track of what to do
|
# This initializes boolean global do_* variables. They keep track of what to do
|
||||||
# -- as the name insinuates
|
# -- as the name insinuates
|
||||||
@ -12439,9 +12490,6 @@ ip=""
|
|||||||
lets_roll init
|
lets_roll init
|
||||||
initialize_globals
|
initialize_globals
|
||||||
parse_cmd_line "$@"
|
parse_cmd_line "$@"
|
||||||
json_header
|
|
||||||
csv_header
|
|
||||||
html_header
|
|
||||||
get_install_dir
|
get_install_dir
|
||||||
set_color_functions
|
set_color_functions
|
||||||
maketempf
|
maketempf
|
||||||
@ -12452,20 +12500,24 @@ mybanner
|
|||||||
check_proxy
|
check_proxy
|
||||||
check4openssl_oldfarts
|
check4openssl_oldfarts
|
||||||
check_bsd_mount
|
check_bsd_mount
|
||||||
|
json_header
|
||||||
|
csv_header
|
||||||
|
html_header
|
||||||
|
|
||||||
if $do_display_only; then
|
if "$do_display_only"; then
|
||||||
prettyprint_local "$PATTERN2SHOW"
|
prettyprint_local "$PATTERN2SHOW"
|
||||||
exit $?
|
exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if $do_mass_testing; then
|
fileout_banner
|
||||||
|
|
||||||
|
if "$do_mass_testing"; then
|
||||||
prepare_logging
|
prepare_logging
|
||||||
run_mass_testing
|
run_mass_testing
|
||||||
exit $?
|
exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
html_banner
|
html_banner
|
||||||
fileout_banner
|
|
||||||
|
|
||||||
#TODO: there shouldn't be the need for a special case for --mx, only the ip adresses we would need upfront and the do-parser
|
#TODO: there shouldn't be the need for a special case for --mx, only the ip adresses we would need upfront and the do-parser
|
||||||
if $do_mx_all_ips; then
|
if $do_mx_all_ips; then
|
||||||
|
Loading…
Reference in New Issue
Block a user