Loading changes/bug11513 0 → 100644 +12 −0 Original line number Diff line number Diff line o Major bugfixes: - Generate the server's preference list for ciphersuites automatically based on uniform criteria, and considering all OpenSSL ciphersuites with acceptable strength and forward secrecy. (The sort order is: prefer AES to 3DES; break ties by preferring ECDHE to DHE; break ties by preferring GCM to CBC; break ties by preferring SHA384 to SHA256 to SHA1; and finally, break ties by preferring AES256 to AES128.) This resolves bugs #11513, #11492, #11498, #11499. Bugs reported by 'cypherpunks'. Bugfix on 0.2.4.8-alpha. src/common/gen_server_ciphers.py 0 → 100755 +115 −0 Original line number Diff line number Diff line #!/usr/bin/python # Copyright 2014, The Tor Project, Inc # See LICENSE for licensing information # This script parses openssl headers to find ciphersuite names, determines # which ones we should be willing to use as a server, and sorts them according # to preference rules. # # Run it on all the files in your openssl include directory. import re import sys EPHEMERAL_INDICATORS = [ "_EDH_", "_DHE_", "_ECDHE_" ] BAD_STUFF = [ "_DES_40_", "MD5", "_RC4_", "_DES_64_", "_SEED_", "_CAMELLIA_", "_NULL" ] # these never get #ifdeffed. MANDATORY = [ "TLS1_TXT_DHE_RSA_WITH_AES_256_SHA", "TLS1_TXT_DHE_RSA_WITH_AES_128_SHA", "SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA", ] def find_ciphers(filename): with open(filename) as f: for line in f: m = re.search(r'(?:SSL3|TLS1)_TXT_\w+', line) if m: yield m.group(0) def usable_cipher(ciph): ephemeral = False for e in EPHEMERAL_INDICATORS: if e in ciph: ephemeral = True if not ephemeral: return False if "_RSA_" not in ciph: return False for b in BAD_STUFF: if b in ciph: return False return True # All fields we sort on, in order of priority. FIELDS = [ 'cipher', 'fwsec', 'mode', 'digest', 'bitlength' ] # Map from sorted fields to recognized value in descending order of goodness FIELD_VALS = { 'cipher' : [ 'AES', 'DES'], 'fwsec' : [ 'ECDHE', 'DHE' ], 'mode' : [ 'GCM', 'CBC' ], 'digest' : [ 'SHA384', 'SHA256', 'SHA' ], 'bitlength' : [ '256', '128', '192' ], } class Ciphersuite(object): def __init__(self, name, fwsec, cipher, bitlength, mode, digest): self.name = name self.fwsec = fwsec self.cipher = cipher self.bitlength = bitlength self.mode = mode self.digest = digest for f in FIELDS: assert(getattr(self, f) in FIELD_VALS[f]) def sort_key(self): return tuple(FIELD_VALS[f].index(getattr(self,f)) for f in FIELDS) def parse_cipher(ciph): m = re.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)(|_CBC|_CBC3|_GCM)_(SHA|SHA256|SHA384)$', ciph) if not m: print "/* Couldn't parse %s ! */"%ciph return None fwsec, cipher, bits, mode, digest = m.groups() if fwsec == 'EDH': fwsec = 'DHE' if mode in [ '_CBC3', '_CBC', '' ]: mode = 'CBC' elif mode == '_GCM': mode = 'GCM' return Ciphersuite(ciph, fwsec, cipher, bits, mode, digest) ALL_CIPHERS = [] for fname in sys.argv[1:]: ALL_CIPHERS += (parse_cipher(c) for c in find_ciphers(fname) if usable_cipher(c) ) ALL_CIPHERS.sort(key=Ciphersuite.sort_key) for c in ALL_CIPHERS: if c is ALL_CIPHERS[-1]: colon = ';' else: colon = ' ":"' if c.name in MANDATORY: print " /* Required */" print ' %s%s'%(c.name,colon) else: print "#ifdef %s"%c.name print ' %s%s'%(c.name,colon) print "#endif" src/common/tortls.c +28 −12 Original line number Diff line number Diff line Loading @@ -714,30 +714,46 @@ tor_tls_create_certificate(crypto_pk_t *rsa, /** List of ciphers that servers should select from when we actually have * our choice of what cipher to use. */ const char UNRESTRICTED_SERVER_CIPHER_LIST[] = #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CHC_SHA TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" #endif /* This list is autogenerated with the gen_server_ciphers.py script; * don't hand-edit it. */ #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 #ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":" #endif #ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":" #endif #ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":" #endif #ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":" #endif //#if TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA // TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA ":" //#endif /* These next two are mandatory. */ /* Required */ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" /* Required */ TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" #ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA ":" #endif /* Required */ SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA; /* Note: to set up your own private testing network with link crypto Loading Loading
changes/bug11513 0 → 100644 +12 −0 Original line number Diff line number Diff line o Major bugfixes: - Generate the server's preference list for ciphersuites automatically based on uniform criteria, and considering all OpenSSL ciphersuites with acceptable strength and forward secrecy. (The sort order is: prefer AES to 3DES; break ties by preferring ECDHE to DHE; break ties by preferring GCM to CBC; break ties by preferring SHA384 to SHA256 to SHA1; and finally, break ties by preferring AES256 to AES128.) This resolves bugs #11513, #11492, #11498, #11499. Bugs reported by 'cypherpunks'. Bugfix on 0.2.4.8-alpha.
src/common/gen_server_ciphers.py 0 → 100755 +115 −0 Original line number Diff line number Diff line #!/usr/bin/python # Copyright 2014, The Tor Project, Inc # See LICENSE for licensing information # This script parses openssl headers to find ciphersuite names, determines # which ones we should be willing to use as a server, and sorts them according # to preference rules. # # Run it on all the files in your openssl include directory. import re import sys EPHEMERAL_INDICATORS = [ "_EDH_", "_DHE_", "_ECDHE_" ] BAD_STUFF = [ "_DES_40_", "MD5", "_RC4_", "_DES_64_", "_SEED_", "_CAMELLIA_", "_NULL" ] # these never get #ifdeffed. MANDATORY = [ "TLS1_TXT_DHE_RSA_WITH_AES_256_SHA", "TLS1_TXT_DHE_RSA_WITH_AES_128_SHA", "SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA", ] def find_ciphers(filename): with open(filename) as f: for line in f: m = re.search(r'(?:SSL3|TLS1)_TXT_\w+', line) if m: yield m.group(0) def usable_cipher(ciph): ephemeral = False for e in EPHEMERAL_INDICATORS: if e in ciph: ephemeral = True if not ephemeral: return False if "_RSA_" not in ciph: return False for b in BAD_STUFF: if b in ciph: return False return True # All fields we sort on, in order of priority. FIELDS = [ 'cipher', 'fwsec', 'mode', 'digest', 'bitlength' ] # Map from sorted fields to recognized value in descending order of goodness FIELD_VALS = { 'cipher' : [ 'AES', 'DES'], 'fwsec' : [ 'ECDHE', 'DHE' ], 'mode' : [ 'GCM', 'CBC' ], 'digest' : [ 'SHA384', 'SHA256', 'SHA' ], 'bitlength' : [ '256', '128', '192' ], } class Ciphersuite(object): def __init__(self, name, fwsec, cipher, bitlength, mode, digest): self.name = name self.fwsec = fwsec self.cipher = cipher self.bitlength = bitlength self.mode = mode self.digest = digest for f in FIELDS: assert(getattr(self, f) in FIELD_VALS[f]) def sort_key(self): return tuple(FIELD_VALS[f].index(getattr(self,f)) for f in FIELDS) def parse_cipher(ciph): m = re.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)(|_CBC|_CBC3|_GCM)_(SHA|SHA256|SHA384)$', ciph) if not m: print "/* Couldn't parse %s ! */"%ciph return None fwsec, cipher, bits, mode, digest = m.groups() if fwsec == 'EDH': fwsec = 'DHE' if mode in [ '_CBC3', '_CBC', '' ]: mode = 'CBC' elif mode == '_GCM': mode = 'GCM' return Ciphersuite(ciph, fwsec, cipher, bits, mode, digest) ALL_CIPHERS = [] for fname in sys.argv[1:]: ALL_CIPHERS += (parse_cipher(c) for c in find_ciphers(fname) if usable_cipher(c) ) ALL_CIPHERS.sort(key=Ciphersuite.sort_key) for c in ALL_CIPHERS: if c is ALL_CIPHERS[-1]: colon = ';' else: colon = ' ":"' if c.name in MANDATORY: print " /* Required */" print ' %s%s'%(c.name,colon) else: print "#ifdef %s"%c.name print ' %s%s'%(c.name,colon) print "#endif"
src/common/tortls.c +28 −12 Original line number Diff line number Diff line Loading @@ -714,30 +714,46 @@ tor_tls_create_certificate(crypto_pk_t *rsa, /** List of ciphers that servers should select from when we actually have * our choice of what cipher to use. */ const char UNRESTRICTED_SERVER_CIPHER_LIST[] = #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CHC_SHA TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" #endif /* This list is autogenerated with the gen_server_ciphers.py script; * don't hand-edit it. */ #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":" #endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 #ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":" #endif #ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":" #endif #ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":" #endif #ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":" #endif //#if TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA // TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA ":" //#endif /* These next two are mandatory. */ /* Required */ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" /* Required */ TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" #ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA ":" #endif /* Required */ SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA; /* Note: to set up your own private testing network with link crypto Loading