summaryrefslogtreecommitdiff
path: root/src/common/get_mozilla_ciphers.py
blob: 9b8af2e0adbd1df4690e55575cd8a80f93c566ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/python
# coding=utf-8
# Copyright 2011, The Tor Project, Inc
# original version by Arturo Filastò

# This script parses Firefox and OpenSSL sources, and uses this information
# to generate a ciphers.inc file.
#
# It takes two arguments: the location of a firefox source directory, and the
# location of an openssl source directory.

import os
import re
import sys

if len(sys.argv) != 3:
    print >>sys.stderr, "Syntax: get_mozilla_ciphers.py <firefox-source-dir> <openssl-source-dir>"
    sys.exit(1)

ff_root = sys.argv[1]
ossl_root = sys.argv[2]

def ff(s):
    return os.path.join(ff_root, s)
def ossl(s):
    return os.path.join(ossl_root, s)

#####
# Read the cpp file to understand what Ciphers map to what name :
# Make "ciphers" a map from name used in the javascript to a cipher macro name
fileA = open(ff('security/manager/ssl/src/nsNSSComponent.cpp'),'r')

# The input format is a file containing exactly one section of the form:
# static CipherPref CipherPrefs[] = {
#  {"name", MACRO_NAME}, // comment
#  ...
#  {NULL, 0}
# }

inCipherSection = False
cipherLines = []
for line in fileA:
    if line.startswith('static CipherPref CipherPrefs'):
        # Get the starting boundary of the Cipher Preferences
        inCipherSection = True
    elif inCipherSection:
        line = line.strip()
        if line.startswith('{NULL, 0}'):
            # At the ending boundary of the Cipher Prefs
            break
        else:
            cipherLines.append(line)
fileA.close()

# Parse the lines and put them into a dict
ciphers = {}
for line in cipherLines:
    m = re.search(r'^{\s*\"([^\"]+)\",\s*(\S*)\s*}', line)
    if m:
        key,value = m.groups()
        ciphers[key] = value

#####
# Read the JS file to understand what ciphers are enabled.  The format is
#  pref("name", true/false);
# Build a map enabled_ciphers from javascript name to "true" or "false",
# and an (unordered!) list of the macro names for those ciphers that are
# enabled.
fileB = open(ff('netwerk/base/public/security-prefs.js'), 'r')

enabled_ciphers = {}
for line in fileB:
    m = re.match(r'pref\(\"([^\"]+)\"\s*,\s*(\S*)\s*\)', line)
    if not m:
        continue
    key, val = m.groups()
    if key.startswith("security.ssl3"):
        enabled_ciphers[key] = val
fileB.close()

used_ciphers = []
for k, v in enabled_ciphers.items():
    if v == "true":
        used_ciphers.append(ciphers[k])

#oSSLinclude = ('/usr/include/openssl/ssl3.h', '/usr/include/openssl/ssl.h',
#               '/usr/include/openssl/ssl2.h', '/usr/include/openssl/ssl23.h',
#               '/usr/include/openssl/tls1.h')
oSSLinclude = ('ssl/ssl3.h', 'ssl/ssl.h',
               'ssl/ssl2.h', 'ssl/ssl23.h',
               'ssl/tls1.h')

#####
# This reads the hex code for the ciphers that are used by firefox.
# sslProtoD is set to a map from macro name to macro value in sslproto.h;
# cipher_codes is set to an (unordered!) list of these hex values.
sslProto = open(ff('security/nss/lib/ssl/sslproto.h'), 'r')
sslProtoD = {}

for line in sslProto:
    m = re.match('#define\s+(\S+)\s+(\S+)', line)
    if m:
        key, value = m.groups()
        sslProtoD[key] = value
sslProto.close()

cipher_codes = []
for x in used_ciphers:
    cipher_codes.append(sslProtoD[x].lower())

####
# Now read through all the openssl include files, and try to find the openssl
# macro names for those files.
cipher_hex = {}
for fl in oSSLinclude:
    fp = open(ossl(fl), 'r')
    for line in fp.readlines():
        m = re.match('#define\s+(\S+)\s+(\S+)', line)
        if m:
            value,key = m.groups()
            if key.startswith('0x'):
                key = key.replace('0x0300','0x').lower()
                #print "%s %s" % (key, value)
                cipher_hex[key] = value
    fp.close()

# Now generate the output.
for x in cipher_codes:
    try:
        res = """#ifdef %s
        CIPHER(%s, %s)
    #else
       XCIPHER(%s, %s)
    #endif""" % (cipher_hex[x], x, cipher_hex[x], x, cipher_hex[x])
        print res
    except KeyError:
        print "Not found %s" % x