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.
11 # Future imports for Python 2.7, mandatory in 3.0
12 from __future__
import division
13 from __future__
import print_function
14 from __future__
import unicode_literals
19 EPHEMERAL_INDICATORS
= [ "_EDH_", "_DHE_", "_ECDHE_" ]
20 BAD_STUFF
= [ "_DES_40_", "MD5", "_RC4_", "_DES_64_",
21 "_SEED_", "_CAMELLIA_", "_NULL",
24 # these never get #ifdeffed.
26 "TLS1_TXT_DHE_RSA_WITH_AES_256_SHA",
27 "TLS1_TXT_DHE_RSA_WITH_AES_128_SHA",
30 def find_ciphers(filename
):
31 with
open(filename
) as f
:
33 m
= re
.search(r
'(?:SSL3|TLS1)_TXT_\w+', line
)
37 def usable_cipher(ciph
):
39 for e
in EPHEMERAL_INDICATORS
:
45 if "_RSA_" not in ciph
:
53 # All fields we sort on, in order of priority.
54 FIELDS
= [ 'cipher', 'fwsec', 'mode', 'digest', 'bitlength' ]
55 # Map from sorted fields to recognized value in descending order of goodness
56 FIELD_VALS
= { 'cipher' : [ 'AES', 'CHACHA20' ],
57 'fwsec' : [ 'ECDHE', 'DHE' ],
58 'mode' : [ 'POLY1305', 'GCM', 'CCM', 'CBC', ],
59 'digest' : [ 'n/a', 'SHA384', 'SHA256', 'SHA', ],
60 'bitlength' : [ '256', '128', '192' ],
63 class Ciphersuite(object):
64 def __init__(self
, name
, fwsec
, cipher
, bitlength
, mode
, digest
):
68 if mode
in [ '_CBC3', '_CBC', '' ]:
76 self
.bitlength
= bitlength
81 assert(getattr(self
, f
) in FIELD_VALS
[f
])
84 return tuple(FIELD_VALS
[f
].index(getattr(self
,f
)) for f
in FIELDS
)
87 def parse_cipher(ciph
):
88 m
= re
.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)(|_CBC|_CBC3|_GCM)_(SHA|SHA256|SHA384)$', ciph
)
91 fwsec
, cipher
, bits
, mode
, digest
= m
.groups()
92 return Ciphersuite(ciph
, fwsec
, cipher
, bits
, mode
, digest
)
94 m
= re
.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)_CCM', ciph
)
96 fwsec
, cipher
, bits
= m
.groups()
97 return Ciphersuite(ciph
, fwsec
, cipher
, bits
, "CCM", "n/a")
99 m
= re
.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_CHACHA20_POLY1305', ciph
)
102 return Ciphersuite(ciph
, fwsec
, "CHACHA20", "256", "POLY1305", "n/a")
104 print("/* Couldn't parse %s ! */"%ciph
)
110 for fname
in sys
.argv
[1:]:
111 for c
in find_ciphers(fname
):
113 parsed
= parse_cipher(c
)
115 ALL_CIPHERS
.append(parsed
)
117 ALL_CIPHERS
.sort(key
=Ciphersuite
.sort_key
)
121 for c
in ALL_CIPHERS
:
122 if c
is ALL_CIPHERS
[-1]:
127 if c
.name
in MANDATORY
:
128 print("%s/* Required */"%indent
)
129 print('%s%s%s'%(indent
,c
.name
,colon
))
131 print("#ifdef %s"%c.name
)
132 print('%s%s%s'%(indent
,c
.name
,colon
))