diff --git a/top1m/parse_results.py b/top1m/parse_results.py index d95d60c..ec17f39 100644 --- a/top1m/parse_results.py +++ b/top1m/parse_results.py @@ -21,9 +21,38 @@ def natural_sort(l): alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] return sorted(l, key = alphanum_key) +""" list of ciphers offerred by Firefox 29 by default """ +firefox_ciphers=[ + 'ECDHE-ECDSA-AES128-GCM-SHA256', + 'ECDHE-RSA-AES128-GCM-SHA256', + 'ECDHE-ECDSA-AES256-SHA', + 'ECDHE-ECDSA-AES128-SHA', + 'ECDHE-RSA-AES128-SHA', + 'ECDHE-RSA-AES256-SHA', + 'ECDHE-RSA-DES-CBC3-SHA', + 'ECDHE-ECDSA-RC4-SHA', + 'ECDHE-RSA-RC4-SHA', + 'DHE-RSA-AES128-SHA', + 'DHE-DSS-AES128-SHA', + 'DHE-RSA-CAMELLIA128-SHA', + 'DHE-RSA-AES256-SHA', + 'DHE-DSS-AES256-SHA', + 'DHE-RSA-CAMELLIA256-SHA', + 'EDH-RSA-DES-CBC3-SHA', + 'AES128-SHA', + 'CAMELLIA128-SHA', + 'AES256-SHA', + 'CAMELLIA256-SHA', + 'DES-CBC3-SHA', + 'RC4-SHA', + 'RC4-MD5'] + report_untrused=False cipherstats = defaultdict(int) +FF_RC4_Only_cipherstats = defaultdict(int) +FF_RC4_preferred_cipherstats = defaultdict(int) +FF_incompatible_cipherstats = defaultdict(int) pfsstats = defaultdict(int) protocolstats = defaultdict(int) handshakestats = defaultdict(int) @@ -53,6 +82,11 @@ for r,d,flist in os.walk(path): DES3 = False CAMELLIA = False RC4 = False + """ the following depends on FF_compat, so by default it can be True """ + RC4_Only_FF = True + FF_compat = False + temp_FF_incompat = {} + FF_RC4_Pref = None ADH = False DHE = False AECDH = False @@ -92,6 +126,20 @@ for r,d,flist in os.walk(path): if 'False' in entry['trusted'] and report_untrused == False: continue + # check if the advertised ciphers are not effectively RC4 Only + # for firefox or incompatible with firefox + if entry['cipher'] in firefox_ciphers: + # if this is first cipher and we already are getting RC4 + # then it means that RC4 is preferred + if not FF_compat: + if 'RC4' in entry['cipher']: + FF_RC4_Pref = True + FF_compat = True + if not 'RC4' in entry['cipher']: + RC4_Only_FF = False + else: + temp_FF_incompat[entry['cipher']] = 1 + """ store the ciphers supported """ if 'ADH' in entry['cipher'] or 'AECDH' in entry['cipher']: ciphertypes += 1 @@ -269,6 +317,20 @@ for r,d,flist in os.walk(path): cipherstats['RC4 forced in TLS1.1+'] += 1 cipherstats['RC4 Preferred'] += 1 + if FF_compat: + if RC4_Only_FF and ciphertypes != 1: + cipherstats['x:FF 29 RC4 Only'] += 1 + for cipher in temp_FF_incompat: + FF_RC4_Only_cipherstats[cipher] += 1 + if FF_RC4_Pref and not 'RC4' in results['ciphersuite'][0]['cipher']: + cipherstats['x:FF 29 RC4 Preferred'] += 1 + for cipher in temp_FF_incompat: + FF_RC4_preferred_cipherstats[cipher] += 1 + else: + cipherstats['x:FF 29 incompatible'] += 1 + for cipher in temp_FF_incompat: + FF_incompatible_cipherstats[cipher] += 1 + for cipher in tempcipherstats: cipherstats[cipher] += 1 @@ -322,6 +384,13 @@ for r,d,flist in os.walk(path): #if total % 1999 == 0: # break +""" The 'x:FF 29 RC4 Preferred' counts only sites that effectively prefer + RC4 when using FF, to make reporting more readable, sum it with sites + that do that for all ciphers""" + +if "x:FF 29 RC4 Preferred" in cipherstats and "RC4 Preferred" in cipherstats: + cipherstats['x:FF 29 RC4 Preferred'] += cipherstats['RC4 Preferred'] + print("SSL/TLS survey of %i websites from Alexa's top 1 million" % total) if report_untrused == False: print("Stats only from connections that did provide valid certificates") @@ -334,6 +403,24 @@ for stat in sorted(cipherstats): percent = round(cipherstats[stat] / total * 100, 4) sys.stdout.write(stat.ljust(25) + " " + str(cipherstats[stat]).ljust(10) + str(percent).ljust(4) + "\n") +print("\nFF 29 RC4 Only other ciphers Count Percent") +print("-----------------------------+---------+------") +for stat in sorted(FF_RC4_Only_cipherstats): + percent = round(FF_RC4_Only_cipherstats[stat] / total * 100, 4) + sys.stdout.write(stat.ljust(30) + " " + str(FF_RC4_Only_cipherstats[stat]).ljust(10) + str(percent).ljust(4) + "\n") + +print("\nFF 29 RC4 pref other ciphers Count Percent") +print("-----------------------------+---------+------") +for stat in sorted(FF_RC4_preferred_cipherstats): + percent = round(FF_RC4_preferred_cipherstats[stat] / total * 100, 4) + sys.stdout.write(stat.ljust(30) + " " + str(FF_RC4_preferred_cipherstats[stat]).ljust(10) + str(percent).ljust(4) + "\n") + +print("\nFF 29 incompatible ciphers Count Percent") +print("-----------------------------+---------+------") +for stat in sorted(FF_incompatible_cipherstats): + percent = round(FF_incompatible_cipherstats[stat] / total * 100, 4) + sys.stdout.write(stat.ljust(30) + " " + str(FF_incompatible_cipherstats[stat]).ljust(10) + str(percent).ljust(4) + "\n") + print("\nSupported Handshakes Count Percent") print("-------------------------+---------+-------") for stat in sorted(handshakestats):