1#!/bin/python3
2
3# Copyright (c) 2024 Nordic Semiconductor ASA
4# Copyright (c) Atmosic 2025
5# SPDX-License-Identifier: Apache-2.0
6
7import re
8import os
9import sys
10import argparse
11from typing import List
12
13SCRIPT_PATH = os.path.dirname(__file__)
14INPUT_REL_PATH = os.path.join("..", "..", "..", "modules", "crypto", "mbedtls",
15                              "include", "psa", "crypto_config.h")
16INPUT_FILE = os.path.normpath(os.path.join(SCRIPT_PATH, INPUT_REL_PATH))
17
18KCONFIG_PATH=os.path.join(SCRIPT_PATH, "Kconfig.psa.auto")
19HEADER_PATH=os.path.join(SCRIPT_PATH, "configs", "config-psa.h")
20
21if sys.platform == "win32":
22    INPUT_REL_PATH = INPUT_REL_PATH.replace("\\", "/")
23
24KCONFIG_HEADER="""\
25# Copyright (c) 2024 Nordic Semiconductor ASA
26# SPDX-License-Identifier: Apache-2.0
27
28# This file was automatically generated by {}
29# from: {}.
30# Do not edit it manually.
31
32config PSA_CRYPTO_CLIENT
33	bool
34	help
35	  Promptless symbol to state that there is a PSA crypto API provider
36	  enabled in the system. This allows to select desired PSA_WANT features.
37
38if PSA_CRYPTO_CLIENT
39
40config PSA_CRYPTO_ENABLE_ALL
41	bool "All PSA crypto features"
42""".format(os.path.basename(__file__), INPUT_REL_PATH)
43
44KCONFIG_FOOTER="\nendif # PSA_CRYPTO_CLIENT\n"
45
46H_HEADER="""\
47/*
48 * Copyright (c) 2024 Nordic Semiconductor ASA
49 *
50 * SPDX-License-Identifier: Apache-2.0
51 */
52
53/* This file was automatically generated by {}
54 * from: {}
55 * Do not edit it manually.
56 */
57
58#ifndef CONFIG_PSA_H
59#define CONFIG_PSA_H
60""".format(os.path.basename(__file__), INPUT_REL_PATH)
61
62H_FOOTER="\n#endif /* CONFIG_PSA_H */\n"
63
64# In Mbed TLS the PSA_WANT_KEY_TYPE_[ECC|RSA|DH]_KEY_PAIR_BASIC build symbols
65# are automatically enabled whenever any other _IMPORT, _EXPORT, _GENERATE or
66# _DERIVE feature is set for the same key type
67# (see "modules/crypto/mbedtls/include/psa/crypto_adjust_config_key_pair_types.h").
68# Therefore we mimic the same pattern with Kconfigs as follows:
69# - do not add _BASIC Kconfigs to the automatic generated file (KCONFIG_PATH);
70# - add _BASIC Kconfigs to Kconfig.psa.logic and let them "default y" as soon as
71#   any other _IMPORT, _EXPORT, _GENERATE or _DERIVE Kconfigs are enabled.
72SKIP_SYMBOLS = [
73    "PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC",
74    "PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC",
75    "PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC"
76]
77
78def parse_psa_symbols(input_file: str):
79    symbols = []
80    with open(input_file) as file:
81        content = file.readlines()
82        for line in content:
83            res = re.findall(r"^#define *(PSA_WANT_\w+)", line)
84            if len(res) > 0:
85                symbols.append(res[0])
86    return symbols
87
88def generate_kconfig_content(symbols: List[str]) -> str:
89    output = []
90    for sym in symbols:
91        if sym in SKIP_SYMBOLS:
92            continue
93        output.append("""
94config {0}
95\tbool "{0}" if !MBEDTLS_PROMPTLESS
96\tdefault y if PSA_CRYPTO_ENABLE_ALL
97""".format(sym))
98
99    return KCONFIG_HEADER + "".join(output) + KCONFIG_FOOTER
100
101def generate_header_content(symbols: List[str]) -> str:
102    output = []
103    for sym in symbols:
104        output.append("""
105#if defined(CONFIG_{0})
106#define {0}   1
107#endif
108""".format(sym))
109
110    return H_HEADER + "".join(output) + H_FOOTER
111
112def generate_output_file(content: str, file_name: str):
113    with open(file_name, "wt") as output_file:
114        output_file.write(content)
115
116def check_file(content: str, file_name: str):
117    file_content = ""
118    with open(file_name) as input_file:
119        file_content = input_file.read()
120        if file_content != content:
121            print()
122            return False
123    return True
124
125def main():
126    arg_parser = argparse.ArgumentParser(allow_abbrev = False)
127    arg_parser.add_argument("--check", action = "store_true", default = False)
128    args = arg_parser.parse_args()
129
130    check_files = args.check
131
132    psa_symbols = parse_psa_symbols(INPUT_FILE)
133    kconfig_content = generate_kconfig_content(psa_symbols)
134    header_content = generate_header_content(psa_symbols)
135
136    if check_files:
137        if ((not check_file(kconfig_content, KCONFIG_PATH)) or
138            (not check_file(header_content, HEADER_PATH))):
139            print("Error: PSA Kconfig and header files do not match with the current"
140                  "version of MbedTLS. Please update them.")
141            sys.exit(1)
142    else:
143        generate_output_file(kconfig_content, KCONFIG_PATH)
144        generate_output_file(header_content, HEADER_PATH)
145
146    sys.exit(0)
147
148if __name__ == "__main__":
149    main()
150