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