Browse Source

Merge remote-tracking branch 'public/bug11513_024'

Nick Mathewson 10 years ago
parent
commit
2704441e7f
3 changed files with 155 additions and 12 deletions
  1. 12 0
      changes/bug11513
  2. 115 0
      src/common/gen_server_ciphers.py
  3. 28 12
      src/common/tortls.c

+ 12 - 0
changes/bug11513

@@ -0,0 +1,12 @@
+  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.
+
+

+ 115 - 0
src/common/gen_server_ciphers.py

@@ -0,0 +1,115 @@
+#!/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"
+
+

+ 28 - 12
src/common/tortls.c

@@ -712,31 +712,47 @@ 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. */
-  TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
-  TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"
+       /* 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
-  SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA;
+       /* Required */
+       SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA;
 
 /* Note: to set up your own private testing network with link crypto
  * disabled, set your Tors' cipher list to