~ubuntu-branches/debian/sid/botan/sid

« back to all changes in this revision

Viewing changes to src/scripts/tls_suite_info.py

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2018-03-01 22:23:25 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20180301222325-7p7vc45gu3hta34d
Tags: 2.4.0-2
* Don't remove .doctrees from the manual if it doesn't exist.
* Don't specify parallel to debhelper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python2
 
2
 
 
3
"""
 
4
Used to generate lib/tls/tls_suite_info.cpp from IANA params
 
5
 
 
6
(C) 2011, 2012, 2013, 2014, 2015, 2016, 2017 Jack Lloyd
 
7
 
 
8
Botan is released under the Simplified BSD License (see license.txt)
 
9
"""
 
10
 
 
11
import sys
 
12
import re
 
13
import datetime
 
14
import hashlib
 
15
import optparse
 
16
 
 
17
def to_ciphersuite_info(code, name):
 
18
 
 
19
    (sig_and_kex,cipher_and_mac) = name.split('_WITH_')
 
20
 
 
21
    if sig_and_kex == 'RSA':
 
22
        sig_algo = 'RSA'
 
23
        kex_algo = 'RSA'
 
24
    elif 'PSK' in sig_and_kex:
 
25
        sig_algo = ''
 
26
        kex_algo = sig_and_kex
 
27
    elif 'SRP' in sig_and_kex:
 
28
        srp_info = sig_and_kex.split('_')
 
29
        if len(srp_info) == 2: # 'SRP_' + hash
 
30
            kex_algo = sig_and_kex
 
31
            sig_algo = ''
 
32
        else:
 
33
            kex_algo = '_'.join(srp_info[0:-1])
 
34
            sig_algo = srp_info[-1]
 
35
    else:
 
36
        (kex_algo, sig_algo) = sig_and_kex.split('_')
 
37
 
 
38
    cipher_and_mac = cipher_and_mac.split('_')
 
39
 
 
40
    mac_algo = cipher_and_mac[-1]
 
41
 
 
42
    cipher = cipher_and_mac[:-1]
 
43
 
 
44
    if mac_algo == '8' and cipher[-1] == 'CCM':
 
45
        cipher = cipher[:-1]
 
46
        mac_algo = 'CCM_8'
 
47
    elif cipher[-2] == 'CCM' and cipher[-1] == '8':
 
48
        cipher = cipher[:-1]
 
49
        mac_algo = 'CCM_8'
 
50
 
 
51
    if mac_algo == 'CCM':
 
52
        cipher += ['CCM']
 
53
        mac_algo = 'SHA256'
 
54
    elif mac_algo == 'CCM_8':
 
55
        cipher += ['CCM(8)']
 
56
        mac_algo = 'SHA256'
 
57
 
 
58
    cipher_info = {
 
59
        'CHACHA20': ('ChaCha',32),
 
60
        'IDEA': ('IDEA',16),
 
61
        'DES': ('DES',8),
 
62
        '3DES': ('3DES',24),
 
63
        'CAMELLIA': ('Camellia',None),
 
64
        'AES': ('AES',None),
 
65
        'SEED': ('SEED',16),
 
66
        'ARIA': ('ARIA',None),
 
67
        }
 
68
 
 
69
    tls_to_botan_names = {
 
70
        'anon': '',
 
71
        'MD5': 'MD5',
 
72
        'SHA': 'SHA-1',
 
73
        'SHA256': 'SHA-256',
 
74
        'SHA384': 'SHA-384',
 
75
        'SHA512': 'SHA-512',
 
76
 
 
77
        'CHACHA': 'ChaCha',
 
78
        '3DES': 'TripleDES',
 
79
 
 
80
        'DSS': 'DSA',
 
81
        'ECDSA': 'ECDSA',
 
82
        'RSA': 'RSA',
 
83
        'SRP_SHA': 'SRP_SHA',
 
84
        'DHE': 'DH',
 
85
        'DH': 'DH',
 
86
        'ECDHE': 'ECDH',
 
87
        'ECDH': 'ECDH',
 
88
        '': '',
 
89
        'PSK': 'PSK',
 
90
        'DHE_PSK': 'DHE_PSK',
 
91
        'PSK_DHE': 'DHE_PSK',
 
92
        'ECDHE_PSK': 'ECDHE_PSK',
 
93
        'CECPQ1': 'CECPQ1',
 
94
        'CECPQ1_PSK': 'CECPQ1_PSK',
 
95
        }
 
96
 
 
97
    mac_keylen = {
 
98
        'MD5': 16,
 
99
        'SHA-1': 20,
 
100
        'SHA-256': 32,
 
101
        'SHA-384': 48,
 
102
        'SHA-512': 64,
 
103
        }
 
104
 
 
105
    mac_algo = tls_to_botan_names[mac_algo]
 
106
    sig_algo = tls_to_botan_names[sig_algo]
 
107
    kex_algo = tls_to_botan_names[kex_algo]
 
108
 
 
109
    (cipher_algo, cipher_keylen) = cipher_info[cipher[0]]
 
110
 
 
111
    if cipher_keylen is None:
 
112
        cipher_keylen = int(cipher[1]) / 8
 
113
 
 
114
    if cipher_algo in ['AES', 'Camellia', 'ARIA']:
 
115
        cipher_algo += '-%d' % (cipher_keylen*8)
 
116
 
 
117
    modestr = ''
 
118
    mode = ''
 
119
    ivlen = 0
 
120
 
 
121
    if cipher[0] == 'CHACHA20' and cipher[1] == 'POLY1305':
 
122
        iv_len = 12
 
123
        if code in ['CC13', 'CC14', 'CC15']:
 
124
            iv_len = 0 # Google variant
 
125
        record_iv_len = 0
 
126
 
 
127
        return (name, code, sig_algo, kex_algo, "ChaCha20Poly1305", cipher_keylen, iv_len, record_iv_len, "AEAD", 0, mac_algo)
 
128
 
 
129
    mode = cipher[-1]
 
130
    if mode not in ['CBC', 'GCM', 'CCM(8)', 'CCM', 'OCB']:
 
131
        print "#warning Unknown mode '%s' for ciphersuite %s (0x%d)" % (' '.join(cipher), name, code)
 
132
 
 
133
    ivlen = 8 if cipher_algo == '3DES' else 16
 
134
 
 
135
    if mode != 'CBC':
 
136
        if mode == 'OCB':
 
137
            cipher_algo += '/OCB(12)'
 
138
        else:
 
139
            cipher_algo += '/' + mode
 
140
 
 
141
    if mode == 'CBC':
 
142
        return (name, code, sig_algo, kex_algo, cipher_algo, cipher_keylen, ivlen, 0, mac_algo, mac_keylen[mac_algo], "")
 
143
 
 
144
    elif mode == 'OCB':
 
145
        return (name, code, sig_algo, kex_algo, cipher_algo, cipher_keylen, 12, 0, "AEAD", 0, mac_algo)
 
146
 
 
147
    else:
 
148
        iv_bytes_from_hs = 4
 
149
        iv_bytes_from_rec = 8
 
150
 
 
151
        return (name, code, sig_algo, kex_algo, cipher_algo, cipher_keylen, iv_bytes_from_hs, iv_bytes_from_rec, "AEAD", 0, mac_algo)
 
152
 
 
153
def open_input(args):
 
154
    iana_url = 'https://www.iana.org/assignments/tls-parameters/tls-parameters.txt'
 
155
 
 
156
    if len(args) == 1:
 
157
        try:
 
158
            return open('tls-parameters.txt')
 
159
        except:
 
160
            pass
 
161
 
 
162
        import urllib2
 
163
        return urllib2.urlopen(iana_url)
 
164
    else:
 
165
         return open(args[1])
 
166
 
 
167
"""
 
168
Handle command line options
 
169
"""
 
170
def process_command_line(args):
 
171
 
 
172
    parser = optparse.OptionParser()
 
173
 
 
174
    parser.add_option('--with-ocb', action='store_true', default=True,
 
175
                      help='enable OCB AEAD suites')
 
176
    parser.add_option('--without-ocb', action='store_false', dest='with_ocb',
 
177
                      help='disable OCB AEAD suites')
 
178
 
 
179
    parser.add_option('--with-aria-cbc', action='store_true', default=False,
 
180
                      help='enable ARIA CBC suites')
 
181
    parser.add_option('--without-aria-cbc', action='store_false', dest='with_aria_cbc',
 
182
                      help='disable ARIA CBC suites')
 
183
 
 
184
    parser.add_option('--with-cecpq1', action='store_true', default=True,
 
185
                      help='enable CECPQ1 suites')
 
186
    parser.add_option('--without-cecpq1', action='store_false', dest='with_cecpq1',
 
187
                      help='disable CECPQ1 suites')
 
188
 
 
189
    parser.add_option('--with-srp-aead', action='store_true', default=False,
 
190
                      help='add SRP AEAD suites')
 
191
    parser.add_option('--without-srp-aead', action='store_false', dest='with_srp_aead',
 
192
                      help='disable SRP AEAD suites')
 
193
 
 
194
    parser.add_option('--save-download', action='store_true', default=False,
 
195
                      help='save downloaded tls-parameters.txt to cwd')
 
196
 
 
197
    parser.add_option('--output', '-o',
 
198
                      help='file to write output to (default %default)',
 
199
                      default='src/lib/tls/tls_suite_info.cpp')
 
200
 
 
201
    return parser.parse_args(args)
 
202
 
 
203
def main(args = None):
 
204
    if args is None:
 
205
        args = sys.argv
 
206
 
 
207
    weak_crypto = ['EXPORT', 'RC2', 'IDEA', 'RC4', '_DES_', 'WITH_NULL']
 
208
    static_dh = ['ECDH_ECDSA', 'ECDH_RSA', 'DH_DSS', 'DH_RSA'] # not supported
 
209
    protocol_goop = ['SCSV', 'KRB5']
 
210
    maybe_someday = ['RSA_PSK']
 
211
    not_supported = weak_crypto + static_dh + protocol_goop + maybe_someday
 
212
 
 
213
    (options, args) = process_command_line(args)
 
214
 
 
215
    if not options.with_aria_cbc:
 
216
        not_supported += ['ARIA_128_CBC', 'ARIA_256_CBC']
 
217
 
 
218
    ciphersuite_re = re.compile(' +0x([0-9a-fA-F][0-9a-fA-F]),0x([0-9a-fA-F][0-9a-fA-F]) + TLS_([A-Za-z_0-9]+) ')
 
219
 
 
220
    suites = {}
 
221
    suite_codes = {}
 
222
 
 
223
    contents = ''
 
224
 
 
225
    for line in open_input(args):
 
226
        contents += line
 
227
        match = ciphersuite_re.match(line)
 
228
        if match:
 
229
            code = match.group(1) + match.group(2)
 
230
            name = match.group(3)
 
231
 
 
232
            should_use = True
 
233
            for ns in not_supported:
 
234
                if ns in name:
 
235
                    should_use = False
 
236
 
 
237
            if should_use:
 
238
                suites[code] = to_ciphersuite_info(code, name)
 
239
 
 
240
    sha1 = hashlib.sha1()
 
241
    sha1.update(contents)
 
242
    contents_hash = sha1.hexdigest()
 
243
 
 
244
    if options.save_download:
 
245
        out = open('tls-parameters.txt', 'w')
 
246
        out.write(contents)
 
247
        out.close()
 
248
 
 
249
    def define_custom_ciphersuite(name, code):
 
250
        suites[code] = to_ciphersuite_info(code, name)
 
251
 
 
252
    # Google servers - draft-agl-tls-chacha20poly1305-04
 
253
    define_custom_ciphersuite('ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256', 'CC13')
 
254
    define_custom_ciphersuite('ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256', 'CC14')
 
255
    define_custom_ciphersuite('DHE_RSA_WITH_CHACHA20_POLY1305_SHA256', 'CC15')
 
256
 
 
257
    if options.with_cecpq1:
 
258
        # CECPQ1 key exchange
 
259
        define_custom_ciphersuite('CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256', '16B7')
 
260
        define_custom_ciphersuite('CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256', '16B8')
 
261
        define_custom_ciphersuite('CECPQ1_RSA_WITH_AES_256_GCM_SHA384', '16B9')
 
262
        define_custom_ciphersuite('CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384', '16BA')
 
263
 
 
264
    if options.with_ocb:
 
265
        # OCB ciphersuites draft-zauner-tls-aes-ocb-04
 
266
        define_custom_ciphersuite('DHE_RSA_WITH_AES_128_OCB_SHA256', 'FFC0')
 
267
        define_custom_ciphersuite('DHE_RSA_WITH_AES_256_OCB_SHA256', 'FFC1')
 
268
        define_custom_ciphersuite('ECDHE_RSA_WITH_AES_128_OCB_SHA256', 'FFC2')
 
269
        define_custom_ciphersuite('ECDHE_RSA_WITH_AES_256_OCB_SHA256', 'FFC3')
 
270
        define_custom_ciphersuite('ECDHE_ECDSA_WITH_AES_128_OCB_SHA256', 'FFC4')
 
271
        define_custom_ciphersuite('ECDHE_ECDSA_WITH_AES_256_OCB_SHA256', 'FFC5')
 
272
 
 
273
        define_custom_ciphersuite('PSK_WITH_AES_128_OCB_SHA256', 'FFC6')
 
274
        define_custom_ciphersuite('PSK_WITH_AES_256_OCB_SHA256', 'FFC7')
 
275
        define_custom_ciphersuite('DHE_PSK_WITH_AES_128_OCB_SHA256', 'FFC8')
 
276
        define_custom_ciphersuite('DHE_PSK_WITH_AES_256_OCB_SHA256', 'FFC9')
 
277
        define_custom_ciphersuite('ECDHE_PSK_WITH_AES_128_OCB_SHA256', 'FFCA')
 
278
        define_custom_ciphersuite('ECDHE_PSK_WITH_AES_256_OCB_SHA256', 'FFCB')
 
279
 
 
280
    if options.with_cecpq1 and options.with_ocb:
 
281
        # CECPQ1 OCB ciphersuites - Botan extension
 
282
        define_custom_ciphersuite('CECPQ1_RSA_WITH_AES_256_OCB_SHA256', 'FFCC')
 
283
        define_custom_ciphersuite('CECPQ1_ECDSA_WITH_AES_256_OCB_SHA256', 'FFCD')
 
284
        #define_custom_ciphersuite('CECPQ1_PSK_WITH_AES_256_OCB_SHA256', 'FFCE')
 
285
 
 
286
    if options.with_srp_aead:
 
287
        # SRP using GCM or OCB - Botan extension
 
288
        define_custom_ciphersuite('SRP_SHA_WITH_AES_256_GCM_SHA384', 'FFA0')
 
289
        define_custom_ciphersuite('SRP_SHA_RSA_WITH_AES_256_GCM_SHA384', 'FFA1')
 
290
        define_custom_ciphersuite('SRP_SHA_DSS_WITH_AES_256_GCM_SHA384', 'FFA2')
 
291
        define_custom_ciphersuite('SRP_SHA_ECDSA_WITH_AES_256_GCM_SHA384', 'FFA3')
 
292
 
 
293
        if options.with_ocb:
 
294
            define_custom_ciphersuite('SRP_SHA_WITH_AES_256_OCB_SHA256', 'FFA4')
 
295
            define_custom_ciphersuite('SRP_SHA_RSA_WITH_AES_256_OCB_SHA256', 'FFA5')
 
296
            define_custom_ciphersuite('SRP_SHA_DSS_WITH_AES_256_OCB_SHA256', 'FFA6')
 
297
            define_custom_ciphersuite('SRP_SHA_ECDSA_WITH_AES_256_OCB_SHA256', 'FFA7')
 
298
 
 
299
    suite_info = ''
 
300
 
 
301
    def header():
 
302
        return """/*
 
303
* TLS cipher suite information
 
304
*
 
305
* This file was automatically generated from the IANA assignments
 
306
* (tls-parameters.txt hash %s)
 
307
* by %s on %s
 
308
*
 
309
* Botan is released under the Simplified BSD License (see license.txt)
 
310
*/
 
311
 
 
312
""" % (contents_hash, sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"))
 
313
 
 
314
    suite_info += header()
 
315
 
 
316
    suite_info += """#include <botan/tls_ciphersuite.h>
 
317
 
 
318
namespace Botan {
 
319
 
 
320
namespace TLS {
 
321
 
 
322
//static
 
323
const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
 
324
   {
 
325
   // Note that this list of ciphersuites is ordered by id!
 
326
   static const std::vector<Ciphersuite> g_ciphersuite_list = {
 
327
"""
 
328
 
 
329
    for code in sorted(suites.keys()):
 
330
        info = suites[code]
 
331
        assert len(info) == 11
 
332
        suite_expr = 'Ciphersuite(0x%s, "%s", "%s", "%s", "%s", %d, %d, %d, "%s", %d, "%s")' % (
 
333
            code, info[0], info[2], info[3], info[4], info[5], info[6], info[7], info[8], info[9], info[10])
 
334
 
 
335
        suite_info += "      " + suite_expr + ",\n"
 
336
        
 
337
 
 
338
    suite_info += """      };
 
339
 
 
340
   return g_ciphersuite_list;
 
341
   }
 
342
 
 
343
}
 
344
 
 
345
}
 
346
"""
 
347
 
 
348
    if options.output == '-':
 
349
        print suite_info,
 
350
    else:
 
351
        out = open(options.output, 'w')
 
352
        out.write(suite_info)
 
353
        out.close()
 
354
 
 
355
if __name__ == '__main__':
 
356
    sys.exit(main())