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