• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2
3"""Generate psa_constant_names_generated.c
4which is included by programs/psa/psa_constant_names.c.
5The code generated by this module is only meant to be used in the context
6of that program.
7
8An argument passed to this script will modify the output directory where the
9file is written:
10* by default (no arguments passed): writes to programs/psa/
11* OUTPUT_FILE_DIR passed: writes to OUTPUT_FILE_DIR/
12"""
13
14# Copyright The Mbed TLS Contributors
15# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
16
17import os
18import sys
19
20from mbedtls_dev import macro_collector
21
22OUTPUT_TEMPLATE = '''\
23/* Automatically generated by generate_psa_constant.py. DO NOT EDIT. */
24
25static const char *psa_strerror(psa_status_t status)
26{
27    switch (status) {
28    %(status_cases)s
29    default: return NULL;
30    }
31}
32
33static const char *psa_ecc_family_name(psa_ecc_family_t curve)
34{
35    switch (curve) {
36    %(ecc_curve_cases)s
37    default: return NULL;
38    }
39}
40
41static const char *psa_dh_family_name(psa_dh_family_t group)
42{
43    switch (group) {
44    %(dh_group_cases)s
45    default: return NULL;
46    }
47}
48
49static const char *psa_hash_algorithm_name(psa_algorithm_t hash_alg)
50{
51    switch (hash_alg) {
52    %(hash_algorithm_cases)s
53    default: return NULL;
54    }
55}
56
57static const char *psa_ka_algorithm_name(psa_algorithm_t ka_alg)
58{
59    switch (ka_alg) {
60    %(ka_algorithm_cases)s
61    default: return NULL;
62    }
63}
64
65static int psa_snprint_key_type(char *buffer, size_t buffer_size,
66                                psa_key_type_t type)
67{
68    size_t required_size = 0;
69    switch (type) {
70    %(key_type_cases)s
71    default:
72        %(key_type_code)s{
73            return snprintf(buffer, buffer_size,
74                            "0x%%04x", (unsigned) type);
75        }
76        break;
77    }
78    buffer[0] = 0;
79    return (int) required_size;
80}
81
82#define NO_LENGTH_MODIFIER 0xfffffffflu
83static int psa_snprint_algorithm(char *buffer, size_t buffer_size,
84                                 psa_algorithm_t alg)
85{
86    size_t required_size = 0;
87    psa_algorithm_t core_alg = alg;
88    unsigned long length_modifier = NO_LENGTH_MODIFIER;
89    if (PSA_ALG_IS_MAC(alg)) {
90        core_alg = PSA_ALG_TRUNCATED_MAC(alg, 0);
91        if (alg & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) {
92            append(&buffer, buffer_size, &required_size,
93                   "PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(", 33);
94            length_modifier = PSA_MAC_TRUNCATED_LENGTH(alg);
95        } else if (core_alg != alg) {
96            append(&buffer, buffer_size, &required_size,
97                   "PSA_ALG_TRUNCATED_MAC(", 22);
98            length_modifier = PSA_MAC_TRUNCATED_LENGTH(alg);
99        }
100    } else if (PSA_ALG_IS_AEAD(alg)) {
101        core_alg = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg);
102        if (core_alg == 0) {
103            /* For unknown AEAD algorithms, there is no "default tag length". */
104            core_alg = alg;
105        } else if (alg & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) {
106            append(&buffer, buffer_size, &required_size,
107                   "PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(", 43);
108            length_modifier = PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
109        } else if (core_alg != alg) {
110            append(&buffer, buffer_size, &required_size,
111                   "PSA_ALG_AEAD_WITH_SHORTENED_TAG(", 32);
112            length_modifier = PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
113        }
114    } else if (PSA_ALG_IS_KEY_AGREEMENT(alg) &&
115               !PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) {
116        core_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF(alg);
117        append(&buffer, buffer_size, &required_size,
118               "PSA_ALG_KEY_AGREEMENT(", 22);
119        append_with_alg(&buffer, buffer_size, &required_size,
120                        psa_ka_algorithm_name,
121                        PSA_ALG_KEY_AGREEMENT_GET_BASE(alg));
122        append(&buffer, buffer_size, &required_size, ", ", 2);
123    }
124    switch (core_alg) {
125    %(algorithm_cases)s
126    default:
127        %(algorithm_code)s{
128            append_integer(&buffer, buffer_size, &required_size,
129                           "0x%%08lx", (unsigned long) core_alg);
130        }
131        break;
132    }
133    if (core_alg != alg) {
134        if (length_modifier != NO_LENGTH_MODIFIER) {
135            append(&buffer, buffer_size, &required_size, ", ", 2);
136            append_integer(&buffer, buffer_size, &required_size,
137                           "%%lu", length_modifier);
138        }
139        append(&buffer, buffer_size, &required_size, ")", 1);
140    }
141    buffer[0] = 0;
142    return (int) required_size;
143}
144
145static int psa_snprint_key_usage(char *buffer, size_t buffer_size,
146                                 psa_key_usage_t usage)
147{
148    size_t required_size = 0;
149    if (usage == 0) {
150        if (buffer_size > 1) {
151            buffer[0] = '0';
152            buffer[1] = 0;
153        } else if (buffer_size == 1) {
154            buffer[0] = 0;
155        }
156        return 1;
157    }
158%(key_usage_code)s
159    if (usage != 0) {
160        if (required_size != 0) {
161            append(&buffer, buffer_size, &required_size, " | ", 3);
162        }
163        append_integer(&buffer, buffer_size, &required_size,
164                       "0x%%08lx", (unsigned long) usage);
165    } else {
166        buffer[0] = 0;
167    }
168    return (int) required_size;
169}
170
171/* End of automatically generated file. */
172'''
173
174KEY_TYPE_FROM_CURVE_TEMPLATE = '''if (%(tester)s(type)) {
175            append_with_curve(&buffer, buffer_size, &required_size,
176                              "%(builder)s", %(builder_length)s,
177                              PSA_KEY_TYPE_ECC_GET_FAMILY(type));
178        } else '''
179
180KEY_TYPE_FROM_GROUP_TEMPLATE = '''if (%(tester)s(type)) {
181            append_with_group(&buffer, buffer_size, &required_size,
182                              "%(builder)s", %(builder_length)s,
183                              PSA_KEY_TYPE_DH_GET_FAMILY(type));
184        } else '''
185
186ALGORITHM_FROM_HASH_TEMPLATE = '''if (%(tester)s(core_alg)) {
187            append(&buffer, buffer_size, &required_size,
188                   "%(builder)s(", %(builder_length)s + 1);
189            append_with_alg(&buffer, buffer_size, &required_size,
190                            psa_hash_algorithm_name,
191                            PSA_ALG_GET_HASH(core_alg));
192            append(&buffer, buffer_size, &required_size, ")", 1);
193        } else '''
194
195BIT_TEST_TEMPLATE = '''\
196    if (%(var)s & %(flag)s) {
197        if (required_size != 0) {
198            append(&buffer, buffer_size, &required_size, " | ", 3);
199        }
200        append(&buffer, buffer_size, &required_size, "%(flag)s", %(length)d);
201        %(var)s ^= %(flag)s;
202    }\
203'''
204
205class CaseBuilder(macro_collector.PSAMacroCollector):
206    """Collect PSA crypto macro definitions and write value recognition functions.
207
208    1. Call `read_file` on the input header file(s).
209    2. Call `write_file` to write ``psa_constant_names_generated.c``.
210    """
211
212    def __init__(self):
213        super().__init__(include_intermediate=True)
214
215    @staticmethod
216    def _make_return_case(name):
217        return 'case %(name)s: return "%(name)s";' % {'name': name}
218
219    @staticmethod
220    def _make_append_case(name):
221        template = ('case %(name)s: '
222                    'append(&buffer, buffer_size, &required_size, "%(name)s", %(length)d); '
223                    'break;')
224        return template % {'name': name, 'length': len(name)}
225
226    @staticmethod
227    def _make_bit_test(var, flag):
228        return BIT_TEST_TEMPLATE % {'var': var,
229                                    'flag': flag,
230                                    'length': len(flag)}
231
232    def _make_status_cases(self):
233        return '\n    '.join(map(self._make_return_case,
234                                 sorted(self.statuses)))
235
236    def _make_ecc_curve_cases(self):
237        return '\n    '.join(map(self._make_return_case,
238                                 sorted(self.ecc_curves)))
239
240    def _make_dh_group_cases(self):
241        return '\n    '.join(map(self._make_return_case,
242                                 sorted(self.dh_groups)))
243
244    def _make_key_type_cases(self):
245        return '\n    '.join(map(self._make_append_case,
246                                 sorted(self.key_types)))
247
248    @staticmethod
249    def _make_key_type_from_curve_code(builder, tester):
250        return KEY_TYPE_FROM_CURVE_TEMPLATE % {'builder': builder,
251                                               'builder_length': len(builder),
252                                               'tester': tester}
253
254    @staticmethod
255    def _make_key_type_from_group_code(builder, tester):
256        return KEY_TYPE_FROM_GROUP_TEMPLATE % {'builder': builder,
257                                               'builder_length': len(builder),
258                                               'tester': tester}
259
260    def _make_ecc_key_type_code(self):
261        d = self.key_types_from_curve
262        make = self._make_key_type_from_curve_code
263        return ''.join([make(k, d[k]) for k in sorted(d.keys())])
264
265    def _make_dh_key_type_code(self):
266        d = self.key_types_from_group
267        make = self._make_key_type_from_group_code
268        return ''.join([make(k, d[k]) for k in sorted(d.keys())])
269
270    def _make_hash_algorithm_cases(self):
271        return '\n    '.join(map(self._make_return_case,
272                                 sorted(self.hash_algorithms)))
273
274    def _make_ka_algorithm_cases(self):
275        return '\n    '.join(map(self._make_return_case,
276                                 sorted(self.ka_algorithms)))
277
278    def _make_algorithm_cases(self):
279        return '\n    '.join(map(self._make_append_case,
280                                 sorted(self.algorithms)))
281
282    @staticmethod
283    def _make_algorithm_from_hash_code(builder, tester):
284        return ALGORITHM_FROM_HASH_TEMPLATE % {'builder': builder,
285                                               'builder_length': len(builder),
286                                               'tester': tester}
287
288    def _make_algorithm_code(self):
289        d = self.algorithms_from_hash
290        make = self._make_algorithm_from_hash_code
291        return ''.join([make(k, d[k]) for k in sorted(d.keys())])
292
293    def _make_key_usage_code(self):
294        return '\n'.join([self._make_bit_test('usage', bit)
295                          for bit in sorted(self.key_usage_flags)])
296
297    def write_file(self, output_file):
298        """Generate the pretty-printer function code from the gathered
299        constant definitions.
300        """
301        data = {}
302        data['status_cases'] = self._make_status_cases()
303        data['ecc_curve_cases'] = self._make_ecc_curve_cases()
304        data['dh_group_cases'] = self._make_dh_group_cases()
305        data['key_type_cases'] = self._make_key_type_cases()
306        data['key_type_code'] = (self._make_ecc_key_type_code() +
307                                 self._make_dh_key_type_code())
308        data['hash_algorithm_cases'] = self._make_hash_algorithm_cases()
309        data['ka_algorithm_cases'] = self._make_ka_algorithm_cases()
310        data['algorithm_cases'] = self._make_algorithm_cases()
311        data['algorithm_code'] = self._make_algorithm_code()
312        data['key_usage_code'] = self._make_key_usage_code()
313        output_file.write(OUTPUT_TEMPLATE % data)
314
315def generate_psa_constants(header_file_names, output_file_name):
316    collector = CaseBuilder()
317    for header_file_name in header_file_names:
318        with open(header_file_name, 'rb') as header_file:
319            collector.read_file(header_file)
320    temp_file_name = output_file_name + '.tmp'
321    with open(temp_file_name, 'w') as output_file:
322        collector.write_file(output_file)
323    os.replace(temp_file_name, output_file_name)
324
325if __name__ == '__main__':
326    if not os.path.isdir('programs') and os.path.isdir('../programs'):
327        os.chdir('..')
328    # Allow to change the directory where psa_constant_names_generated.c is written to.
329    OUTPUT_FILE_DIR = sys.argv[1] if len(sys.argv) == 2 else "programs/psa"
330    generate_psa_constants(['include/psa/crypto_values.h',
331                            'include/psa/crypto_extra.h'],
332                           OUTPUT_FILE_DIR + '/psa_constant_names_generated.c')
333