2 # Copyright 2014-2019, The Tor Project, Inc
3 # See LICENSE for licensing information
5 # This script parses openssl headers to find ciphersuite names, determines
6 # which ones we should be willing to use as a server, and sorts them according
9 # Run it on all the files in your openssl include directory.
14 EPHEMERAL_INDICATORS
= [ "_EDH_", "_DHE_", "_ECDHE_" ]
15 BAD_STUFF
= [ "_DES_40_", "MD5", "_RC4_", "_DES_64_",
16 "_SEED_", "_CAMELLIA_", "_NULL",
19 # these never get #ifdeffed.
21 "TLS1_TXT_DHE_RSA_WITH_AES_256_SHA",
22 "TLS1_TXT_DHE_RSA_WITH_AES_128_SHA",
25 def find_ciphers(filename
):
26 with
open(filename
) as f
:
28 m
= re
.search(r
'(?:SSL3|TLS1)_TXT_\w+', line
)
32 def usable_cipher(ciph
):
34 for e
in EPHEMERAL_INDICATORS
:
40 if "_RSA_" not in ciph
:
48 # All fields we sort on, in order of priority.
49 FIELDS
= [ 'cipher', 'fwsec', 'mode', 'digest', 'bitlength' ]
50 # Map from sorted fields to recognized value in descending order of goodness
51 FIELD_VALS
= { 'cipher' : [ 'AES', 'CHACHA20' ],
52 'fwsec' : [ 'ECDHE', 'DHE' ],
53 'mode' : [ 'POLY1305', 'GCM', 'CCM', 'CBC', ],
54 'digest' : [ 'n/a', 'SHA384', 'SHA256', 'SHA', ],
55 'bitlength' : [ '256', '128', '192' ],
58 class Ciphersuite(object):
59 def __init__(self
, name
, fwsec
, cipher
, bitlength
, mode
, digest
):
63 if mode
in [ '_CBC3', '_CBC', '' ]:
71 self
.bitlength
= bitlength
76 assert(getattr(self
, f
) in FIELD_VALS
[f
])
79 return tuple(FIELD_VALS
[f
].index(getattr(self
,f
)) for f
in FIELDS
)
82 def parse_cipher(ciph
):
83 m
= re
.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)(|_CBC|_CBC3|_GCM)_(SHA|SHA256|SHA384)$', ciph
)
86 fwsec
, cipher
, bits
, mode
, digest
= m
.groups()
87 return Ciphersuite(ciph
, fwsec
, cipher
, bits
, mode
, digest
)
89 m
= re
.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)_CCM', ciph
)
91 fwsec
, cipher
, bits
= m
.groups()
92 return Ciphersuite(ciph
, fwsec
, cipher
, bits
, "CCM", "n/a")
94 m
= re
.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_CHACHA20_POLY1305', ciph
)
97 return Ciphersuite(ciph
, fwsec
, "CHACHA20", "256", "POLY1305", "n/a")
99 print "/* Couldn't parse %s ! */"%ciph
105 for fname
in sys
.argv
[1:]:
106 for c
in find_ciphers(fname
):
108 parsed
= parse_cipher(c
)
110 ALL_CIPHERS
.append(parsed
)
112 ALL_CIPHERS
.sort(key
=Ciphersuite
.sort_key
)
116 for c
in ALL_CIPHERS
:
117 if c
is ALL_CIPHERS
[-1]:
122 if c
.name
in MANDATORY
:
123 print "%s/* Required */"%indent
124 print '%s%s%s'%(indent
,c
.name
,colon
)
126 print "#ifdef %s"%c.name
127 print '%s%s%s'%(indent
,c
.name
,colon
)