blob: dac60034d490b91386f46b2358b2695302fc6f16 [file] [log] [blame]
Gilles Peskine029b5d62018-07-16 23:13:37 +02001#!/usr/bin/env python
2import os
3import re
4import sys
5
6output_template = '''\
7/* Automatically generated by generate_psa_constant.py. DO NOT EDIT. */
8
9static const char *psa_strerror(psa_status_t status)
10{
11 switch (status) {
12 %(status_cases)s
13 default: return NULL;
14 }
15}
16
17static const char *psa_ecc_curve_name(psa_ecc_curve_t curve)
18{
19 switch (curve) {
20 %(ecc_curve_cases)s
21 default: return NULL;
22 }
23}
24
25static const char *psa_hash_algorithm_name(psa_algorithm_t hash_alg)
26{
27 switch (hash_alg) {
28 %(hash_algorithm_cases)s
29 default: return NULL;
30 }
31}
32
Gilles Peskine882e57e2019-04-12 00:12:07 +020033static const char *psa_ka_algorithm_name(psa_algorithm_t ka_alg)
34{
35 switch (ka_alg) {
36 %(ka_algorithm_cases)s
37 default: return NULL;
38 }
39}
40
Gilles Peskine029b5d62018-07-16 23:13:37 +020041static int psa_snprint_key_type(char *buffer, size_t buffer_size,
42 psa_key_type_t type)
43{
44 size_t required_size = 0;
45 switch (type) {
46 %(key_type_cases)s
47 default:
48 %(key_type_code)s{
49 return snprintf(buffer, buffer_size,
50 "0x%%08lx", (unsigned long) type);
51 }
52 break;
53 }
54 buffer[0] = 0;
Darryl Green18246962018-10-17 15:01:45 +010055 return (int) required_size;
Gilles Peskine029b5d62018-07-16 23:13:37 +020056}
57
Gilles Peskine882e57e2019-04-12 00:12:07 +020058#define NO_LENGTH_MODIFIER 0xfffffffflu
Gilles Peskine029b5d62018-07-16 23:13:37 +020059static int psa_snprint_algorithm(char *buffer, size_t buffer_size,
60 psa_algorithm_t alg)
61{
62 size_t required_size = 0;
Gilles Peskine498c2a12018-08-20 15:07:20 +020063 psa_algorithm_t core_alg = alg;
Gilles Peskine882e57e2019-04-12 00:12:07 +020064 unsigned long length_modifier = NO_LENGTH_MODIFIER;
Gilles Peskine498c2a12018-08-20 15:07:20 +020065 if (PSA_ALG_IS_MAC(alg)) {
66 core_alg = PSA_ALG_TRUNCATED_MAC(alg, 0);
67 if (core_alg != alg) {
68 append(&buffer, buffer_size, &required_size,
69 "PSA_ALG_TRUNCATED_MAC(", 22);
70 length_modifier = PSA_MAC_TRUNCATED_LENGTH(alg);
71 }
72 } else if (PSA_ALG_IS_AEAD(alg)) {
73 core_alg = PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH(alg);
Gilles Peskine182c2e92018-10-19 11:33:51 +020074 if (core_alg == 0) {
Darryl Greendf723062019-02-06 15:36:00 +000075 /* For unknown AEAD algorithms, there is no "default tag length". */
Gilles Peskine182c2e92018-10-19 11:33:51 +020076 core_alg = alg;
77 } else if (core_alg != alg) {
Gilles Peskine498c2a12018-08-20 15:07:20 +020078 append(&buffer, buffer_size, &required_size,
79 "PSA_ALG_AEAD_WITH_TAG_LENGTH(", 29);
80 length_modifier = PSA_AEAD_TAG_LENGTH(alg);
81 }
Gilles Peskine882e57e2019-04-12 00:12:07 +020082 } else if (PSA_ALG_IS_KEY_AGREEMENT(alg) &&
83 !PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) {
84 core_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF(alg);
85 append(&buffer, buffer_size, &required_size,
86 "PSA_ALG_KEY_AGREEMENT(", 22);
87 append_with_alg(&buffer, buffer_size, &required_size,
88 psa_ka_algorithm_name,
89 PSA_ALG_KEY_AGREEMENT_GET_BASE(alg));
90 append(&buffer, buffer_size, &required_size, ", ", 2);
Gilles Peskine498c2a12018-08-20 15:07:20 +020091 }
92 switch (core_alg) {
Gilles Peskine029b5d62018-07-16 23:13:37 +020093 %(algorithm_cases)s
94 default:
95 %(algorithm_code)s{
Gilles Peskine0deaf3d2018-08-20 15:06:39 +020096 append_integer(&buffer, buffer_size, &required_size,
Gilles Peskine182c2e92018-10-19 11:33:51 +020097 "0x%%08lx", (unsigned long) core_alg);
Gilles Peskine029b5d62018-07-16 23:13:37 +020098 }
99 break;
100 }
Gilles Peskine498c2a12018-08-20 15:07:20 +0200101 if (core_alg != alg) {
Gilles Peskine882e57e2019-04-12 00:12:07 +0200102 if (length_modifier != NO_LENGTH_MODIFIER) {
103 append(&buffer, buffer_size, &required_size, ", ", 2);
104 append_integer(&buffer, buffer_size, &required_size,
105 "%%lu", length_modifier);
106 }
Gilles Peskine498c2a12018-08-20 15:07:20 +0200107 append(&buffer, buffer_size, &required_size, ")", 1);
108 }
Gilles Peskine029b5d62018-07-16 23:13:37 +0200109 buffer[0] = 0;
Darryl Green18246962018-10-17 15:01:45 +0100110 return (int) required_size;
Gilles Peskine029b5d62018-07-16 23:13:37 +0200111}
112
113static int psa_snprint_key_usage(char *buffer, size_t buffer_size,
114 psa_key_usage_t usage)
115{
116 size_t required_size = 0;
117 if (usage == 0) {
118 if (buffer_size > 1) {
119 buffer[0] = '0';
120 buffer[1] = 0;
121 } else if (buffer_size == 1) {
122 buffer[0] = 0;
123 }
124 return 1;
125 }
126%(key_usage_code)s
127 if (usage != 0) {
128 if (required_size != 0) {
129 append(&buffer, buffer_size, &required_size, " | ", 3);
130 }
Gilles Peskine0deaf3d2018-08-20 15:06:39 +0200131 append_integer(&buffer, buffer_size, &required_size,
132 "0x%%08lx", (unsigned long) usage);
Gilles Peskine029b5d62018-07-16 23:13:37 +0200133 } else {
134 buffer[0] = 0;
135 }
Darryl Green18246962018-10-17 15:01:45 +0100136 return (int) required_size;
Gilles Peskine029b5d62018-07-16 23:13:37 +0200137}
138
139/* End of automatically generated file. */
140'''
141
142key_type_from_curve_template = '''if (%(tester)s(type)) {
Gilles Peskineddeb55a2018-08-02 15:08:07 +0200143 append_with_curve(&buffer, buffer_size, &required_size,
144 "%(builder)s", %(builder_length)s,
145 PSA_KEY_TYPE_GET_CURVE(type));
146 } else '''
Gilles Peskine029b5d62018-07-16 23:13:37 +0200147
Gilles Peskine498c2a12018-08-20 15:07:20 +0200148algorithm_from_hash_template = '''if (%(tester)s(core_alg)) {
Gilles Peskine882e57e2019-04-12 00:12:07 +0200149 append(&buffer, buffer_size, &required_size,
150 "%(builder)s(", %(builder_length)s + 1);
151 append_with_alg(&buffer, buffer_size, &required_size,
152 psa_hash_algorithm_name,
153 PSA_ALG_GET_HASH(core_alg));
154 append(&buffer, buffer_size, &required_size, ")", 1);
Gilles Peskineddeb55a2018-08-02 15:08:07 +0200155 } else '''
Gilles Peskine029b5d62018-07-16 23:13:37 +0200156
157bit_test_template = '''\
158 if (%(var)s & %(flag)s) {
159 if (required_size != 0) {
160 append(&buffer, buffer_size, &required_size, " | ", 3);
161 }
162 append(&buffer, buffer_size, &required_size, "%(flag)s", %(length)d);
163 %(var)s ^= %(flag)s;
164 }\
165'''
166
167class MacroCollector:
168 def __init__(self):
169 self.statuses = set()
170 self.key_types = set()
171 self.key_types_from_curve = {}
172 self.ecc_curves = set()
173 self.algorithms = set()
174 self.hash_algorithms = set()
Gilles Peskine882e57e2019-04-12 00:12:07 +0200175 self.ka_algorithms = set()
Gilles Peskine029b5d62018-07-16 23:13:37 +0200176 self.algorithms_from_hash = {}
177 self.key_usages = set()
178
179 # "#define" followed by a macro name with either no parameters
180 # or a single parameter. Grab the macro name in group 1, the
181 # parameter name if any in group 2 and the definition in group 3.
182 definition_re = re.compile(r'\s*#\s*define\s+(\w+)(?:\s+|\((\w+)\)\s*)(.+)(?:/[*/])?')
183
184 def read_line(self, line):
185 m = re.match(self.definition_re, line)
186 if not m:
187 return
188 name, parameter, definition = m.groups()
189 if name.endswith('_FLAG') or name.endswith('MASK'):
190 # Macro only to build actual values
191 return
192 elif (name.startswith('PSA_ERROR_') or name == 'PSA_SUCCESS') \
193 and not parameter:
Jaeden Amero5e6d24c2019-02-21 10:41:29 +0000194 if name in [
195 'PSA_ERROR_UNKNOWN_ERROR',
196 'PSA_ERROR_OCCUPIED_SLOT',
197 'PSA_ERROR_EMPTY_SLOT',
198 'PSA_ERROR_INSUFFICIENT_CAPACITY',
199 ]:
200 # Ad hoc skipping of deprecated error codes, which share
201 # numerical values with non-deprecated error codes
202 return
203
Gilles Peskine029b5d62018-07-16 23:13:37 +0200204 self.statuses.add(name)
205 elif name.startswith('PSA_KEY_TYPE_') and not parameter:
206 self.key_types.add(name)
207 elif name.startswith('PSA_KEY_TYPE_') and parameter == 'curve':
208 self.key_types_from_curve[name] = name[:13] + 'IS_' + name[13:]
209 elif name.startswith('PSA_ECC_CURVE_') and not parameter:
210 self.ecc_curves.add(name)
Gilles Peskine029b5d62018-07-16 23:13:37 +0200211 elif name.startswith('PSA_ALG_') and not parameter:
Gilles Peskinedaea26f2018-08-21 14:02:45 +0200212 if name in ['PSA_ALG_ECDSA_BASE',
Gilles Peskine029b5d62018-07-16 23:13:37 +0200213 'PSA_ALG_RSA_PKCS1V15_SIGN_BASE']:
214 # Ad hoc skipping of duplicate names for some numerical values
215 return
216 self.algorithms.add(name)
217 # Ad hoc detection of hash algorithms
218 if re.search(r'0x010000[0-9A-Fa-f]{2}', definition):
219 self.hash_algorithms.add(name)
Gilles Peskine882e57e2019-04-12 00:12:07 +0200220 # Ad hoc detection of key agreement algorithms
221 if re.search(r'0x30[0-9A-Fa-f]{2}0000', definition):
222 self.ka_algorithms.add(name)
Gilles Peskine029b5d62018-07-16 23:13:37 +0200223 elif name.startswith('PSA_ALG_') and parameter == 'hash_alg':
224 if name in ['PSA_ALG_DSA', 'PSA_ALG_ECDSA']:
225 # A naming irregularity
226 tester = name[:8] + 'IS_RANDOMIZED_' + name[8:]
227 else:
228 tester = name[:8] + 'IS_' + name[8:]
229 self.algorithms_from_hash[name] = tester
230 elif name.startswith('PSA_KEY_USAGE_') and not parameter:
231 self.key_usages.add(name)
232 else:
233 # Other macro without parameter
234 return
235
236 def read_file(self, header_file):
237 for line in header_file:
238 self.read_line(line)
239
240 def make_return_case(self, name):
241 return 'case %(name)s: return "%(name)s";' % {'name': name}
242
243 def make_append_case(self, name):
244 template = ('case %(name)s: '
245 'append(&buffer, buffer_size, &required_size, "%(name)s", %(length)d); '
246 'break;')
247 return template % {'name': name, 'length': len(name)}
248
249 def make_inner_append_case(self, name):
250 template = ('case %(name)s: '
251 'append(buffer, buffer_size, required_size, "%(name)s", %(length)d); '
252 'break;')
253 return template % {'name': name, 'length': len(name)}
254
255 def make_bit_test(self, var, flag):
256 return bit_test_template % {'var': var,
257 'flag': flag,
258 'length': len(flag)}
259
260 def make_status_cases(self):
261 return '\n '.join(map(self.make_return_case,
262 sorted(self.statuses)))
263
264 def make_ecc_curve_cases(self):
265 return '\n '.join(map(self.make_return_case,
266 sorted(self.ecc_curves)))
267
268 def make_key_type_cases(self):
269 return '\n '.join(map(self.make_append_case,
270 sorted(self.key_types)))
271
272 def make_key_type_from_curve_code(self, builder, tester):
273 return key_type_from_curve_template % {'builder': builder,
274 'builder_length': len(builder),
275 'tester': tester}
276
277 def make_key_type_code(self):
278 d = self.key_types_from_curve
279 make = self.make_key_type_from_curve_code
Gilles Peskineddeb55a2018-08-02 15:08:07 +0200280 return ''.join([make(k, d[k]) for k in sorted(d.keys())])
Gilles Peskine029b5d62018-07-16 23:13:37 +0200281
282 def make_hash_algorithm_cases(self):
283 return '\n '.join(map(self.make_return_case,
284 sorted(self.hash_algorithms)))
285
Gilles Peskine882e57e2019-04-12 00:12:07 +0200286 def make_ka_algorithm_cases(self):
287 return '\n '.join(map(self.make_return_case,
288 sorted(self.ka_algorithms)))
289
Gilles Peskine029b5d62018-07-16 23:13:37 +0200290 def make_algorithm_cases(self):
291 return '\n '.join(map(self.make_append_case,
292 sorted(self.algorithms)))
293
294 def make_algorithm_from_hash_code(self, builder, tester):
295 return algorithm_from_hash_template % {'builder': builder,
296 'builder_length': len(builder),
297 'tester': tester}
298
299 def make_algorithm_code(self):
300 d = self.algorithms_from_hash
301 make = self.make_algorithm_from_hash_code
Gilles Peskineddeb55a2018-08-02 15:08:07 +0200302 return ''.join([make(k, d[k]) for k in sorted(d.keys())])
Gilles Peskine029b5d62018-07-16 23:13:37 +0200303
304 def make_key_usage_code(self):
305 return '\n'.join([self.make_bit_test('usage', bit)
306 for bit in sorted(self.key_usages)])
307
308 def write_file(self, output_file):
309 data = {}
310 data['status_cases'] = self.make_status_cases()
311 data['ecc_curve_cases'] = self.make_ecc_curve_cases()
312 data['key_type_cases'] = self.make_key_type_cases()
313 data['key_type_code'] = self.make_key_type_code()
314 data['hash_algorithm_cases'] = self.make_hash_algorithm_cases()
Gilles Peskine882e57e2019-04-12 00:12:07 +0200315 data['ka_algorithm_cases'] = self.make_ka_algorithm_cases()
Gilles Peskine029b5d62018-07-16 23:13:37 +0200316 data['algorithm_cases'] = self.make_algorithm_cases()
317 data['algorithm_code'] = self.make_algorithm_code()
318 data['key_usage_code'] = self.make_key_usage_code()
319 output_file.write(output_template % data)
320
Gilles Peskine6d194bd2019-01-04 19:44:59 +0100321def generate_psa_constants(header_file_names, output_file_name):
Gilles Peskine029b5d62018-07-16 23:13:37 +0200322 collector = MacroCollector()
Gilles Peskine6d194bd2019-01-04 19:44:59 +0100323 for header_file_name in header_file_names:
324 with open(header_file_name) as header_file:
325 collector.read_file(header_file)
Gilles Peskine029b5d62018-07-16 23:13:37 +0200326 temp_file_name = output_file_name + '.tmp'
327 with open(temp_file_name, 'w') as output_file:
328 collector.write_file(output_file)
329 os.rename(temp_file_name, output_file_name)
330
331if __name__ == '__main__':
332 if not os.path.isdir('programs') and os.path.isdir('../programs'):
333 os.chdir('..')
Gilles Peskine6d194bd2019-01-04 19:44:59 +0100334 generate_psa_constants(['include/psa/crypto_values.h',
335 'include/psa/crypto_extra.h'],
Gilles Peskine029b5d62018-07-16 23:13:37 +0200336 'programs/psa/psa_constant_names_generated.c')