]>
Commit | Line | Data |
---|---|---|
057303f8 SS |
1 | #!/usr/bin/python |
2 | # vim:set et sw=4: | |
3 | # | |
4 | # certdata2pem.py - splits certdata.txt into multiple files | |
5 | # | |
6 | # Copyright (C) 2009 Philipp Kern <pkern@debian.org> | |
7 | # | |
8 | # This program is free software; you can redistribute it and/or modify | |
9 | # it under the terms of the GNU General Public License as published by | |
10 | # the Free Software Foundation; either version 2 of the License, or | |
11 | # (at your option) any later version. | |
12 | # | |
13 | # This program is distributed in the hope that it will be useful, | |
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | # GNU General Public License for more details. | |
17 | # | |
18 | # You should have received a copy of the GNU General Public License | |
19 | # along with this program; if not, write to the Free Software | |
20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, | |
21 | # USA. | |
22 | ||
23 | import base64 | |
24 | import os.path | |
25 | import re | |
26 | import sys | |
27 | import textwrap | |
28 | ||
29 | objects = [] | |
30 | ||
31 | # Dirty file parser. | |
32 | in_data, in_multiline, in_obj = False, False, False | |
33 | field, type, value, obj = None, None, None, dict() | |
34 | for line in open('certdata.txt', 'r'): | |
35 | # Ignore the file header. | |
36 | if not in_data: | |
37 | if line.startswith('BEGINDATA'): | |
38 | in_data = True | |
39 | continue | |
40 | # Ignore comment lines. | |
41 | if line.startswith('#'): | |
42 | continue | |
43 | # Empty lines are significant if we are inside an object. | |
44 | if in_obj and len(line.strip()) == 0: | |
45 | objects.append(obj) | |
46 | obj = dict() | |
47 | in_obj = False | |
48 | continue | |
49 | if len(line.strip()) == 0: | |
50 | continue | |
51 | if in_multiline: | |
52 | if not line.startswith('END'): | |
53 | if type == 'MULTILINE_OCTAL': | |
54 | line = line.strip() | |
55 | for i in re.finditer(r'\\([0-3][0-7][0-7])', line): | |
56 | value += chr(int(i.group(1), 8)) | |
57 | else: | |
58 | value += line | |
59 | continue | |
60 | obj[field] = value | |
61 | in_multiline = False | |
62 | continue | |
63 | if line.startswith('CKA_CLASS'): | |
64 | in_obj = True | |
65 | line_parts = line.strip().split(' ', 2) | |
66 | if len(line_parts) > 2: | |
67 | field, type = line_parts[0:2] | |
68 | value = ' '.join(line_parts[2:]) | |
69 | elif len(line_parts) == 2: | |
70 | field, type = line_parts | |
71 | value = None | |
72 | else: | |
73 | raise NotImplementedError, 'line_parts < 2 not supported.' | |
74 | if type == 'MULTILINE_OCTAL': | |
75 | in_multiline = True | |
76 | value = "" | |
77 | continue | |
78 | obj[field] = value | |
79 | if len(obj.items()) > 0: | |
80 | objects.append(obj) | |
81 | ||
82 | # Read blacklist. | |
83 | blacklist = [] | |
84 | if os.path.exists('blacklist.txt'): | |
85 | for line in open('blacklist.txt', 'r'): | |
86 | line = line.strip() | |
87 | if line.startswith('#') or len(line) == 0: | |
88 | continue | |
89 | item = line.split('#', 1)[0].strip() | |
90 | blacklist.append(item) | |
91 | ||
92 | # Build up trust database. | |
93 | trust = dict() | |
94 | trustmap = dict() | |
95 | for obj in objects: | |
96 | ||
97 | if obj['CKA_CLASS'] != 'CKO_NSS_TRUST': | |
98 | continue | |
99 | if obj['CKA_LABEL'] in blacklist: | |
100 | print "Certificate %s blacklisted, ignoring." % obj['CKA_LABEL'] | |
101 | elif obj['CKA_TRUST_SERVER_AUTH'] == 'CKT_NSS_TRUSTED_DELEGATOR': | |
102 | trust[obj['CKA_LABEL']] = True | |
103 | elif obj['CKA_TRUST_EMAIL_PROTECTION'] == 'CKT_NSS_TRUSTED_DELEGATOR': | |
104 | trust[obj['CKA_LABEL']] = True | |
105 | elif obj['CKA_TRUST_CODE_SIGNING'] == 'CKT_NSS_TRUSTED_DELEGATOR': | |
106 | trust[obj['CKA_LABEL']] = True | |
107 | elif obj['CKA_TRUST_SERVER_AUTH'] == 'CKT_NSS_UNTRUSTED': | |
108 | print '!'*74 | |
109 | print "UNTRUSTED BUT NOT BLACKLISTED CERTIFICATE FOUND: %s" % obj['CKA_LABEL'] | |
110 | print '!'*74 | |
111 | sys.exit(1) | |
112 | else: | |
113 | print "Ignoring certificate %s. SAUTH=%s, EPROT=%s" % \ | |
114 | (obj['CKA_LABEL'], obj['CKA_TRUST_SERVER_AUTH'], | |
115 | obj['CKA_TRUST_EMAIL_PROTECTION']) | |
116 | label = obj['CKA_LABEL'] | |
117 | trustmap[label] = obj | |
118 | print " added cert", label | |
119 | ||
120 | def obj_to_filename(obj): | |
121 | label = obj['CKA_LABEL'][1:-1] | |
122 | label = label.replace('/', '_')\ | |
123 | .replace(' ', '_')\ | |
124 | .replace('(', '=')\ | |
125 | .replace(')', '=')\ | |
126 | .replace(',', '_') | |
127 | label = re.sub(r'\\x[0-9a-fA-F]{2}', lambda m:chr(int(m.group(0)[2:], 16)), label) | |
128 | serial = ".".join(map(lambda x:str(ord(x)), obj['CKA_SERIAL_NUMBER'])) | |
129 | return label + ":" + serial + ".crt" | |
130 | ||
131 | trust_types = { | |
132 | "CKA_TRUST_DIGITAL_SIGNATURE": "digital-signature", | |
133 | "CKA_TRUST_NON_REPUDIATION": "non-repudiation", | |
134 | "CKA_TRUST_KEY_ENCIPHERMENT": "key-encipherment", | |
135 | "CKA_TRUST_DATA_ENCIPHERMENT": "data-encipherment", | |
136 | "CKA_TRUST_KEY_AGREEMENT": "key-agreement", | |
137 | "CKA_TRUST_KEY_CERT_SIGN": "cert-sign", | |
138 | "CKA_TRUST_CRL_SIGN": "crl-sign", | |
139 | "CKA_TRUST_SERVER_AUTH": "server-auth", | |
140 | "CKA_TRUST_CLIENT_AUTH": "client-auth", | |
141 | "CKA_TRUST_CODE_SIGNING": "code-signing", | |
142 | "CKA_TRUST_EMAIL_PROTECTION": "email-protection", | |
143 | "CKA_TRUST_IPSEC_END_SYSTEM": "ipsec-end-system", | |
144 | "CKA_TRUST_IPSEC_TUNNEL": "ipsec-tunnel", | |
145 | "CKA_TRUST_IPSEC_USER": "ipsec-user", | |
146 | "CKA_TRUST_TIME_STAMPING": "time-stamping", | |
147 | "CKA_TRUST_STEP_UP_APPROVED": "step-up-approved", | |
148 | } | |
149 | ||
150 | openssl_trust = { | |
151 | "CKA_TRUST_SERVER_AUTH": "serverAuth", | |
152 | "CKA_TRUST_CLIENT_AUTH": "clientAuth", | |
153 | "CKA_TRUST_CODE_SIGNING": "codeSigning", | |
154 | "CKA_TRUST_EMAIL_PROTECTION": "emailProtection", | |
155 | } | |
156 | ||
157 | for obj in objects: | |
158 | if obj['CKA_CLASS'] == 'CKO_CERTIFICATE': | |
159 | print "producing cert file for " + obj['CKA_LABEL'] | |
160 | if not obj['CKA_LABEL'] in trust or not trust[obj['CKA_LABEL']]: | |
161 | print " -> untrusted, ignoring" | |
162 | continue | |
163 | fname = obj_to_filename(obj) | |
164 | f = open(fname, 'w') | |
165 | trustbits = [] | |
166 | openssl_trustflags = [] | |
167 | tobj = trustmap[obj['CKA_LABEL']] | |
168 | for t in trust_types.keys(): | |
169 | if tobj.has_key(t) and tobj[t] == 'CKT_NSS_TRUSTED_DELEGATOR': | |
170 | trustbits.append(t) | |
171 | if t in openssl_trust: | |
172 | openssl_trustflags.append(openssl_trust[t]) | |
173 | f.write("# trust=" + " ".join(trustbits) + "\n") | |
174 | if openssl_trustflags: | |
175 | f.write("# openssl-trust=" + " ".join(openssl_trustflags) + "\n") | |
176 | f.write("-----BEGIN CERTIFICATE-----\n") | |
177 | f.write("\n".join(textwrap.wrap(base64.b64encode(obj['CKA_VALUE']), 64))) | |
178 | f.write("\n-----END CERTIFICATE-----\n") | |
179 | print " -> written as '%s', trust = %s, openssl-trust = %s" % (fname, trustbits, openssl_trustflags) | |
180 | ||
181 | ||
182 |