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