mirror of
https://github.com/Mbed-TLS/mbedtls-framework.git
synced 2026-08-01 08:47:46 +00:00
Move some files to framework repository
Signed-off-by: Gilles Peskine <[email protected]>
This commit is contained in:
@@ -1,677 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""This script compares the interfaces of two versions of Mbed TLS, looking
|
||||
for backward incompatibilities between two different Git revisions within
|
||||
an Mbed TLS repository. It must be run from the root of a Git working tree.
|
||||
|
||||
### How the script works ###
|
||||
|
||||
For the source (API) and runtime (ABI) interface compatibility, this script
|
||||
is a small wrapper around the abi-compliance-checker and abi-dumper tools,
|
||||
applying them to compare the header and library files.
|
||||
|
||||
For the storage format, this script compares the automatically generated
|
||||
storage tests and the manual read tests, and complains if there is a
|
||||
reduction in coverage. A change in test data will be signaled as a
|
||||
coverage reduction since the old test data is no longer present. A change in
|
||||
how test data is presented will be signaled as well; this would be a false
|
||||
positive.
|
||||
|
||||
The results of the API/ABI comparison are either formatted as HTML and stored
|
||||
at a configurable location, or are given as a brief list of problems.
|
||||
Returns 0 on success, 1 on non-compliance, and 2 if there is an error
|
||||
while running the script.
|
||||
|
||||
### How to interpret non-compliance ###
|
||||
|
||||
This script has relatively common false positives. In many scenarios, it only
|
||||
reports a pass if there is a strict textual match between the old version and
|
||||
the new version, and it reports problems where there is a sufficient semantic
|
||||
match but not a textual match. This section lists some common false positives.
|
||||
This is not an exhaustive list: in the end what matters is whether we are
|
||||
breaking a backward compatibility goal.
|
||||
|
||||
**API**: the goal is that if an application works with the old version of the
|
||||
library, it can be recompiled against the new version and will still work.
|
||||
This is normally validated by comparing the declarations in `include/*/*.h`.
|
||||
A failure is a declaration that has disappeared or that now has a different
|
||||
type.
|
||||
|
||||
* It's ok to change or remove macros and functions that are documented as
|
||||
for internal use only or as experimental.
|
||||
* It's ok to rename function or macro parameters as long as the semantics
|
||||
has not changed.
|
||||
* It's ok to change or remove structure fields that are documented as
|
||||
private.
|
||||
* It's ok to add fields to a structure that already had private fields
|
||||
or was documented as extensible.
|
||||
|
||||
**ABI**: the goal is that if an application was built against the old version
|
||||
of the library, the same binary will work when linked against the new version.
|
||||
This is normally validated by comparing the symbols exported by `libmbed*.so`.
|
||||
A failure is a symbol that is no longer exported by the same library or that
|
||||
now has a different type.
|
||||
|
||||
* All ABI changes are acceptable if the library version is bumped
|
||||
(see `scripts/bump_version.sh`).
|
||||
* ABI changes that concern functions which are declared only inside the
|
||||
library directory, and not in `include/*/*.h`, are acceptable only if
|
||||
the function was only ever used inside the same library (libmbedcrypto,
|
||||
libmbedx509, libmbedtls). As a counter example, if the old version
|
||||
of libmbedtls calls mbedtls_foo() from libmbedcrypto, and the new version
|
||||
of libmbedcrypto no longer has a compatible mbedtls_foo(), this does
|
||||
require a version bump for libmbedcrypto.
|
||||
|
||||
**Storage format**: the goal is to check that persistent keys stored by the
|
||||
old version can be read by the new version. This is normally validated by
|
||||
comparing the `*read*` test cases in `test_suite*storage_format*.data`.
|
||||
A failure is a storage read test case that is no longer present with the same
|
||||
function name and parameter list.
|
||||
|
||||
* It's ok if the same test data is present, but its presentation has changed,
|
||||
for example if a test function is renamed or has different parameters.
|
||||
* It's ok if redundant tests are removed.
|
||||
|
||||
**Generated test coverage**: the goal is to check that automatically
|
||||
generated tests have as much coverage as before. This is normally validated
|
||||
by comparing the test cases that are automatically generated by a script.
|
||||
A failure is a generated test case that is no longer present with the same
|
||||
function name and parameter list.
|
||||
|
||||
* It's ok if the same test data is present, but its presentation has changed,
|
||||
for example if a test function is renamed or has different parameters.
|
||||
* It's ok if redundant tests are removed.
|
||||
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
import shutil
|
||||
import subprocess
|
||||
import argparse
|
||||
import logging
|
||||
import tempfile
|
||||
import fnmatch
|
||||
from types import SimpleNamespace
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import build_tree
|
||||
|
||||
|
||||
class AbiChecker:
|
||||
"""API and ABI checker."""
|
||||
|
||||
def __init__(self, old_version, new_version, configuration):
|
||||
"""Instantiate the API/ABI checker.
|
||||
|
||||
old_version: RepoVersion containing details to compare against
|
||||
new_version: RepoVersion containing details to check
|
||||
configuration.report_dir: directory for output files
|
||||
configuration.keep_all_reports: if false, delete old reports
|
||||
configuration.brief: if true, output shorter report to stdout
|
||||
configuration.check_abi: if true, compare ABIs
|
||||
configuration.check_api: if true, compare APIs
|
||||
configuration.check_storage: if true, compare storage format tests
|
||||
configuration.skip_file: path to file containing symbols and types to skip
|
||||
"""
|
||||
self.repo_path = "."
|
||||
self.log = None
|
||||
self.verbose = configuration.verbose
|
||||
self._setup_logger()
|
||||
self.report_dir = os.path.abspath(configuration.report_dir)
|
||||
self.keep_all_reports = configuration.keep_all_reports
|
||||
self.can_remove_report_dir = not (os.path.exists(self.report_dir) or
|
||||
self.keep_all_reports)
|
||||
self.old_version = old_version
|
||||
self.new_version = new_version
|
||||
self.skip_file = configuration.skip_file
|
||||
self.check_abi = configuration.check_abi
|
||||
self.check_api = configuration.check_api
|
||||
if self.check_abi != self.check_api:
|
||||
raise Exception('Checking API without ABI or vice versa is not supported')
|
||||
self.check_storage_tests = configuration.check_storage
|
||||
self.brief = configuration.brief
|
||||
self.git_command = "git"
|
||||
self.make_command = "make"
|
||||
|
||||
def _setup_logger(self):
|
||||
self.log = logging.getLogger()
|
||||
if self.verbose:
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
else:
|
||||
self.log.setLevel(logging.INFO)
|
||||
self.log.addHandler(logging.StreamHandler())
|
||||
|
||||
@staticmethod
|
||||
def check_abi_tools_are_installed():
|
||||
for command in ["abi-dumper", "abi-compliance-checker"]:
|
||||
if not shutil.which(command):
|
||||
raise Exception("{} not installed, aborting".format(command))
|
||||
|
||||
def _get_clean_worktree_for_git_revision(self, version):
|
||||
"""Make a separate worktree with version.revision checked out.
|
||||
Do not modify the current worktree."""
|
||||
git_worktree_path = tempfile.mkdtemp()
|
||||
if version.repository:
|
||||
self.log.debug(
|
||||
"Checking out git worktree for revision {} from {}".format(
|
||||
version.revision, version.repository
|
||||
)
|
||||
)
|
||||
fetch_output = subprocess.check_output(
|
||||
[self.git_command, "fetch",
|
||||
version.repository, version.revision],
|
||||
cwd=self.repo_path,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(fetch_output.decode("utf-8"))
|
||||
worktree_rev = "FETCH_HEAD"
|
||||
else:
|
||||
self.log.debug("Checking out git worktree for revision {}".format(
|
||||
version.revision
|
||||
))
|
||||
worktree_rev = version.revision
|
||||
worktree_output = subprocess.check_output(
|
||||
[self.git_command, "worktree", "add", "--detach",
|
||||
git_worktree_path, worktree_rev],
|
||||
cwd=self.repo_path,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(worktree_output.decode("utf-8"))
|
||||
version.commit = subprocess.check_output(
|
||||
[self.git_command, "rev-parse", "HEAD"],
|
||||
cwd=git_worktree_path,
|
||||
stderr=subprocess.STDOUT
|
||||
).decode("ascii").rstrip()
|
||||
self.log.debug("Commit is {}".format(version.commit))
|
||||
return git_worktree_path
|
||||
|
||||
def _update_git_submodules(self, git_worktree_path, version):
|
||||
"""If the crypto submodule is present, initialize it.
|
||||
if version.crypto_revision exists, update it to that revision,
|
||||
otherwise update it to the default revision"""
|
||||
update_output = subprocess.check_output(
|
||||
[self.git_command, "submodule", "update", "--init", '--recursive'],
|
||||
cwd=git_worktree_path,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(update_output.decode("utf-8"))
|
||||
if not (os.path.exists(os.path.join(git_worktree_path, "crypto"))
|
||||
and version.crypto_revision):
|
||||
return
|
||||
|
||||
if version.crypto_repository:
|
||||
fetch_output = subprocess.check_output(
|
||||
[self.git_command, "fetch", version.crypto_repository,
|
||||
version.crypto_revision],
|
||||
cwd=os.path.join(git_worktree_path, "crypto"),
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(fetch_output.decode("utf-8"))
|
||||
crypto_rev = "FETCH_HEAD"
|
||||
else:
|
||||
crypto_rev = version.crypto_revision
|
||||
|
||||
checkout_output = subprocess.check_output(
|
||||
[self.git_command, "checkout", crypto_rev],
|
||||
cwd=os.path.join(git_worktree_path, "crypto"),
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(checkout_output.decode("utf-8"))
|
||||
|
||||
def _build_shared_libraries(self, git_worktree_path, version):
|
||||
"""Build the shared libraries in the specified worktree."""
|
||||
my_environment = os.environ.copy()
|
||||
my_environment["CFLAGS"] = "-g -Og"
|
||||
my_environment["SHARED"] = "1"
|
||||
if os.path.exists(os.path.join(git_worktree_path, "crypto")):
|
||||
my_environment["USE_CRYPTO_SUBMODULE"] = "1"
|
||||
make_output = subprocess.check_output(
|
||||
[self.make_command, "lib"],
|
||||
env=my_environment,
|
||||
cwd=git_worktree_path,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(make_output.decode("utf-8"))
|
||||
for root, _dirs, files in os.walk(git_worktree_path):
|
||||
for file in fnmatch.filter(files, "*.so"):
|
||||
version.modules[os.path.splitext(file)[0]] = (
|
||||
os.path.join(root, file)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _pretty_revision(version):
|
||||
if version.revision == version.commit:
|
||||
return version.revision
|
||||
else:
|
||||
return "{} ({})".format(version.revision, version.commit)
|
||||
|
||||
def _get_abi_dumps_from_shared_libraries(self, version):
|
||||
"""Generate the ABI dumps for the specified git revision.
|
||||
The shared libraries must have been built and the module paths
|
||||
present in version.modules."""
|
||||
for mbed_module, module_path in version.modules.items():
|
||||
output_path = os.path.join(
|
||||
self.report_dir, "{}-{}-{}.dump".format(
|
||||
mbed_module, version.revision, version.version
|
||||
)
|
||||
)
|
||||
abi_dump_command = [
|
||||
"abi-dumper",
|
||||
module_path,
|
||||
"-o", output_path,
|
||||
"-lver", self._pretty_revision(version),
|
||||
]
|
||||
abi_dump_output = subprocess.check_output(
|
||||
abi_dump_command,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(abi_dump_output.decode("utf-8"))
|
||||
version.abi_dumps[mbed_module] = output_path
|
||||
|
||||
@staticmethod
|
||||
def _normalize_storage_test_case_data(line):
|
||||
"""Eliminate cosmetic or irrelevant details in storage format test cases."""
|
||||
line = re.sub(r'\s+', r'', line)
|
||||
return line
|
||||
|
||||
def _read_storage_tests(self,
|
||||
directory,
|
||||
filename,
|
||||
is_generated,
|
||||
storage_tests):
|
||||
"""Record storage tests from the given file.
|
||||
|
||||
Populate the storage_tests dictionary with test cases read from
|
||||
filename under directory.
|
||||
"""
|
||||
at_paragraph_start = True
|
||||
description = None
|
||||
full_path = os.path.join(directory, filename)
|
||||
with open(full_path) as fd:
|
||||
for line_number, line in enumerate(fd, 1):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
at_paragraph_start = True
|
||||
continue
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
if at_paragraph_start:
|
||||
description = line.strip()
|
||||
at_paragraph_start = False
|
||||
continue
|
||||
if line.startswith('depends_on:'):
|
||||
continue
|
||||
# We've reached a test case data line
|
||||
test_case_data = self._normalize_storage_test_case_data(line)
|
||||
if not is_generated:
|
||||
# In manual test data, only look at read tests.
|
||||
function_name = test_case_data.split(':', 1)[0]
|
||||
if 'read' not in function_name.split('_'):
|
||||
continue
|
||||
metadata = SimpleNamespace(
|
||||
filename=filename,
|
||||
line_number=line_number,
|
||||
description=description
|
||||
)
|
||||
storage_tests[test_case_data] = metadata
|
||||
|
||||
@staticmethod
|
||||
def _list_generated_test_data_files(git_worktree_path):
|
||||
"""List the generated test data files."""
|
||||
generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
|
||||
if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
|
||||
# The checked-out revision is from before generate_psa_tests.py
|
||||
# was moved to the framework submodule. Use the old location.
|
||||
generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
|
||||
|
||||
output = subprocess.check_output(
|
||||
[generate_psa_tests, '--list'],
|
||||
cwd=git_worktree_path,
|
||||
).decode('ascii')
|
||||
return [line for line in output.split('\n') if line]
|
||||
|
||||
def _get_storage_format_tests(self, version, git_worktree_path):
|
||||
"""Record the storage format tests for the specified git version.
|
||||
|
||||
The storage format tests are the test suite data files whose name
|
||||
contains "storage_format".
|
||||
|
||||
The version must be checked out at git_worktree_path.
|
||||
|
||||
This function creates or updates the generated data files.
|
||||
"""
|
||||
# Existing test data files. This may be missing some automatically
|
||||
# generated files if they haven't been generated yet.
|
||||
if os.path.isdir(os.path.join(git_worktree_path, 'tf-psa-crypto',
|
||||
'tests', 'suites')):
|
||||
storage_data_files = set(glob.glob(
|
||||
'tf-psa-crypto/tests/suites/test_suite_*storage_format*.data'
|
||||
))
|
||||
else:
|
||||
storage_data_files = set(glob.glob(
|
||||
'tests/suites/test_suite_*storage_format*.data'
|
||||
))
|
||||
# Discover and (re)generate automatically generated data files.
|
||||
to_be_generated = set()
|
||||
for filename in self._list_generated_test_data_files(git_worktree_path):
|
||||
if 'storage_format' in filename:
|
||||
storage_data_files.add(filename)
|
||||
to_be_generated.add(filename)
|
||||
|
||||
generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
|
||||
if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
|
||||
# The checked-out revision is from before generate_psa_tests.py
|
||||
# was moved to the framework submodule. Use the old location.
|
||||
generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
|
||||
subprocess.check_call(
|
||||
[generate_psa_tests] + sorted(to_be_generated),
|
||||
cwd=git_worktree_path,
|
||||
)
|
||||
for test_file in sorted(storage_data_files):
|
||||
self._read_storage_tests(git_worktree_path,
|
||||
test_file,
|
||||
test_file in to_be_generated,
|
||||
version.storage_tests)
|
||||
|
||||
def _cleanup_worktree(self, git_worktree_path):
|
||||
"""Remove the specified git worktree."""
|
||||
shutil.rmtree(git_worktree_path)
|
||||
worktree_output = subprocess.check_output(
|
||||
[self.git_command, "worktree", "prune"],
|
||||
cwd=self.repo_path,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
self.log.debug(worktree_output.decode("utf-8"))
|
||||
|
||||
def _get_abi_dump_for_ref(self, version):
|
||||
"""Generate the interface information for the specified git revision."""
|
||||
git_worktree_path = self._get_clean_worktree_for_git_revision(version)
|
||||
self._update_git_submodules(git_worktree_path, version)
|
||||
if self.check_abi:
|
||||
self._build_shared_libraries(git_worktree_path, version)
|
||||
self._get_abi_dumps_from_shared_libraries(version)
|
||||
if self.check_storage_tests:
|
||||
self._get_storage_format_tests(version, git_worktree_path)
|
||||
self._cleanup_worktree(git_worktree_path)
|
||||
|
||||
def _remove_children_with_tag(self, parent, tag):
|
||||
children = parent.getchildren()
|
||||
for child in children:
|
||||
if child.tag == tag:
|
||||
parent.remove(child)
|
||||
else:
|
||||
self._remove_children_with_tag(child, tag)
|
||||
|
||||
def _remove_extra_detail_from_report(self, report_root):
|
||||
for tag in ['test_info', 'test_results', 'problem_summary',
|
||||
'added_symbols', 'affected']:
|
||||
self._remove_children_with_tag(report_root, tag)
|
||||
|
||||
for report in report_root:
|
||||
for problems in report.getchildren()[:]:
|
||||
if not problems.getchildren():
|
||||
report.remove(problems)
|
||||
|
||||
def _abi_compliance_command(self, mbed_module, output_path):
|
||||
"""Build the command to run to analyze the library mbed_module.
|
||||
The report will be placed in output_path."""
|
||||
abi_compliance_command = [
|
||||
"abi-compliance-checker",
|
||||
"-l", mbed_module,
|
||||
"-old", self.old_version.abi_dumps[mbed_module],
|
||||
"-new", self.new_version.abi_dumps[mbed_module],
|
||||
"-strict",
|
||||
"-report-path", output_path,
|
||||
]
|
||||
if self.skip_file:
|
||||
abi_compliance_command += ["-skip-symbols", self.skip_file,
|
||||
"-skip-types", self.skip_file]
|
||||
if self.brief:
|
||||
abi_compliance_command += ["-report-format", "xml",
|
||||
"-stdout"]
|
||||
return abi_compliance_command
|
||||
|
||||
def _is_library_compatible(self, mbed_module, compatibility_report):
|
||||
"""Test if the library mbed_module has remained compatible.
|
||||
Append a message regarding compatibility to compatibility_report."""
|
||||
output_path = os.path.join(
|
||||
self.report_dir, "{}-{}-{}.html".format(
|
||||
mbed_module, self.old_version.revision,
|
||||
self.new_version.revision
|
||||
)
|
||||
)
|
||||
try:
|
||||
subprocess.check_output(
|
||||
self._abi_compliance_command(mbed_module, output_path),
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
except subprocess.CalledProcessError as err:
|
||||
if err.returncode != 1:
|
||||
raise err
|
||||
if self.brief:
|
||||
self.log.info(
|
||||
"Compatibility issues found for {}".format(mbed_module)
|
||||
)
|
||||
report_root = ET.fromstring(err.output.decode("utf-8"))
|
||||
self._remove_extra_detail_from_report(report_root)
|
||||
self.log.info(ET.tostring(report_root).decode("utf-8"))
|
||||
else:
|
||||
self.can_remove_report_dir = False
|
||||
compatibility_report.append(
|
||||
"Compatibility issues found for {}, "
|
||||
"for details see {}".format(mbed_module, output_path)
|
||||
)
|
||||
return False
|
||||
compatibility_report.append(
|
||||
"No compatibility issues for {}".format(mbed_module)
|
||||
)
|
||||
if not (self.keep_all_reports or self.brief):
|
||||
os.remove(output_path)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _is_storage_format_compatible(old_tests, new_tests,
|
||||
compatibility_report):
|
||||
"""Check whether all tests present in old_tests are also in new_tests.
|
||||
|
||||
Append a message regarding compatibility to compatibility_report.
|
||||
"""
|
||||
missing = frozenset(old_tests.keys()).difference(new_tests.keys())
|
||||
for test_data in sorted(missing):
|
||||
metadata = old_tests[test_data]
|
||||
compatibility_report.append(
|
||||
'Test case from {} line {} "{}" has disappeared: {}'.format(
|
||||
metadata.filename, metadata.line_number,
|
||||
metadata.description, test_data
|
||||
)
|
||||
)
|
||||
compatibility_report.append(
|
||||
'FAIL: {}/{} storage format test cases have changed or disappeared.'.format(
|
||||
len(missing), len(old_tests)
|
||||
) if missing else
|
||||
'PASS: All {} storage format test cases are preserved.'.format(
|
||||
len(old_tests)
|
||||
)
|
||||
)
|
||||
compatibility_report.append(
|
||||
'Info: number of storage format tests cases: {} -> {}.'.format(
|
||||
len(old_tests), len(new_tests)
|
||||
)
|
||||
)
|
||||
return not missing
|
||||
|
||||
def get_abi_compatibility_report(self):
|
||||
"""Generate a report of the differences between the reference ABI
|
||||
and the new ABI. ABI dumps from self.old_version and self.new_version
|
||||
must be available."""
|
||||
compatibility_report = ["Checking evolution from {} to {}".format(
|
||||
self._pretty_revision(self.old_version),
|
||||
self._pretty_revision(self.new_version)
|
||||
)]
|
||||
compliance_return_code = 0
|
||||
|
||||
if self.check_abi:
|
||||
shared_modules = list(set(self.old_version.modules.keys()) &
|
||||
set(self.new_version.modules.keys()))
|
||||
for mbed_module in shared_modules:
|
||||
if not self._is_library_compatible(mbed_module,
|
||||
compatibility_report):
|
||||
compliance_return_code = 1
|
||||
|
||||
if self.check_storage_tests:
|
||||
if not self._is_storage_format_compatible(
|
||||
self.old_version.storage_tests,
|
||||
self.new_version.storage_tests,
|
||||
compatibility_report):
|
||||
compliance_return_code = 1
|
||||
|
||||
for version in [self.old_version, self.new_version]:
|
||||
for mbed_module, mbed_module_dump in version.abi_dumps.items():
|
||||
os.remove(mbed_module_dump)
|
||||
if self.can_remove_report_dir:
|
||||
os.rmdir(self.report_dir)
|
||||
self.log.info("\n".join(compatibility_report))
|
||||
return compliance_return_code
|
||||
|
||||
def check_for_abi_changes(self):
|
||||
"""Generate a report of ABI differences
|
||||
between self.old_rev and self.new_rev."""
|
||||
build_tree.check_repo_path()
|
||||
if self.check_api or self.check_abi:
|
||||
self.check_abi_tools_are_installed()
|
||||
self._get_abi_dump_for_ref(self.old_version)
|
||||
self._get_abi_dump_for_ref(self.new_version)
|
||||
return self.get_abi_compatibility_report()
|
||||
|
||||
|
||||
def run_main():
|
||||
try:
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", action="store_true",
|
||||
help="set verbosity level",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r", "--report-dir", type=str, default="reports",
|
||||
help="directory where reports are stored, default is reports",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-k", "--keep-all-reports", action="store_true",
|
||||
help="keep all reports, even if there are no compatibility issues",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o", "--old-rev", type=str, help="revision for old version.",
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-or", "--old-repo", type=str, help="repository for old version."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-oc", "--old-crypto-rev", type=str,
|
||||
help="revision for old crypto submodule."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-ocr", "--old-crypto-repo", type=str,
|
||||
help="repository for old crypto submodule."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n", "--new-rev", type=str, help="revision for new version",
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-nr", "--new-repo", type=str, help="repository for new version."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-nc", "--new-crypto-rev", type=str,
|
||||
help="revision for new crypto version"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-ncr", "--new-crypto-repo", type=str,
|
||||
help="repository for new crypto submodule."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s", "--skip-file", type=str,
|
||||
help=("path to file containing symbols and types to skip "
|
||||
"(typically \"-s identifiers\" after running "
|
||||
"\"tests/scripts/list-identifiers.sh --internal\")")
|
||||
)
|
||||
parser.add_argument(
|
||||
"--check-abi",
|
||||
action='store_true', default=True,
|
||||
help="Perform ABI comparison (default: yes)"
|
||||
)
|
||||
parser.add_argument("--no-check-abi", action='store_false', dest='check_abi')
|
||||
parser.add_argument(
|
||||
"--check-api",
|
||||
action='store_true', default=True,
|
||||
help="Perform API comparison (default: yes)"
|
||||
)
|
||||
parser.add_argument("--no-check-api", action='store_false', dest='check_api')
|
||||
parser.add_argument(
|
||||
"--check-storage",
|
||||
action='store_true', default=True,
|
||||
help="Perform storage tests comparison (default: yes)"
|
||||
)
|
||||
parser.add_argument("--no-check-storage", action='store_false', dest='check_storage')
|
||||
parser.add_argument(
|
||||
"-b", "--brief", action="store_true",
|
||||
help="output only the list of issues to stdout, instead of a full report",
|
||||
)
|
||||
abi_args = parser.parse_args()
|
||||
if os.path.isfile(abi_args.report_dir):
|
||||
print("Error: {} is not a directory".format(abi_args.report_dir))
|
||||
parser.exit()
|
||||
old_version = SimpleNamespace(
|
||||
version="old",
|
||||
repository=abi_args.old_repo,
|
||||
revision=abi_args.old_rev,
|
||||
commit=None,
|
||||
crypto_repository=abi_args.old_crypto_repo,
|
||||
crypto_revision=abi_args.old_crypto_rev,
|
||||
abi_dumps={},
|
||||
storage_tests={},
|
||||
modules={}
|
||||
)
|
||||
new_version = SimpleNamespace(
|
||||
version="new",
|
||||
repository=abi_args.new_repo,
|
||||
revision=abi_args.new_rev,
|
||||
commit=None,
|
||||
crypto_repository=abi_args.new_crypto_repo,
|
||||
crypto_revision=abi_args.new_crypto_rev,
|
||||
abi_dumps={},
|
||||
storage_tests={},
|
||||
modules={}
|
||||
)
|
||||
configuration = SimpleNamespace(
|
||||
verbose=abi_args.verbose,
|
||||
report_dir=abi_args.report_dir,
|
||||
keep_all_reports=abi_args.keep_all_reports,
|
||||
brief=abi_args.brief,
|
||||
check_abi=abi_args.check_abi,
|
||||
check_api=abi_args.check_api,
|
||||
check_storage=abi_args.check_storage,
|
||||
skip_file=abi_args.skip_file
|
||||
)
|
||||
abi_check = AbiChecker(old_version, new_version, configuration)
|
||||
return_code = abi_check.check_for_abi_changes()
|
||||
sys.exit(return_code)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# Print the backtrace and exit explicitly so as to exit with
|
||||
# status 2, not 1.
|
||||
traceback.print_exc()
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_main()
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Generate doxygen documentation with a full mbedtls_config.h (this ensures that every
|
||||
# available flag is documented, and avoids warnings about documentation
|
||||
# without a corresponding #define).
|
||||
#
|
||||
# /!\ This must not be a Makefile target, as it would create a race condition
|
||||
# when multiple targets are invoked in the same parallel build.
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
set -eu
|
||||
|
||||
CONFIG_H='include/mbedtls/mbedtls_config.h'
|
||||
|
||||
if [ -r $CONFIG_H ]; then :; else
|
||||
echo "$CONFIG_H not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONFIG_BAK=${CONFIG_H}.bak
|
||||
cp -p $CONFIG_H $CONFIG_BAK
|
||||
|
||||
scripts/config.py realfull
|
||||
make apidoc
|
||||
|
||||
mv $CONFIG_BAK $CONFIG_H
|
||||
@@ -1,534 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Assemble Mbed TLS change log entries into the change log file.
|
||||
|
||||
Add changelog entries to the first level-2 section.
|
||||
Create a new level-2 section for unreleased changes if needed.
|
||||
Remove the input files unless --keep-entries is specified.
|
||||
|
||||
In each level-3 section, entries are sorted in chronological order
|
||||
(oldest first). From oldest to newest:
|
||||
* Merged entry files are sorted according to their merge date (date of
|
||||
the merge commit that brought the commit that created the file into
|
||||
the target branch).
|
||||
* Committed but unmerged entry files are sorted according to the date
|
||||
of the commit that adds them.
|
||||
* Uncommitted entry files are sorted according to their modification time.
|
||||
|
||||
You must run this program from within a git working directory.
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import argparse
|
||||
from collections import OrderedDict, namedtuple
|
||||
import datetime
|
||||
import functools
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
class InputFormatError(Exception):
|
||||
def __init__(self, filename, line_number, message, *args, **kwargs):
|
||||
message = '{}:{}: {}'.format(filename, line_number,
|
||||
message.format(*args, **kwargs))
|
||||
super().__init__(message)
|
||||
|
||||
class CategoryParseError(Exception):
|
||||
def __init__(self, line_offset, error_message):
|
||||
self.line_offset = line_offset
|
||||
self.error_message = error_message
|
||||
super().__init__('{}: {}'.format(line_offset, error_message))
|
||||
|
||||
class LostContent(Exception):
|
||||
def __init__(self, filename, line):
|
||||
message = ('Lost content from {}: "{}"'.format(filename, line))
|
||||
super().__init__(message)
|
||||
|
||||
class FilePathError(Exception):
|
||||
def __init__(self, filenames):
|
||||
message = ('Changelog filenames do not end with .txt: {}'.format(", ".join(filenames)))
|
||||
super().__init__(message)
|
||||
|
||||
# The category names we use in the changelog.
|
||||
# If you edit this, update ChangeLog.d/README.md.
|
||||
STANDARD_CATEGORIES = (
|
||||
'API changes',
|
||||
'Default behavior changes',
|
||||
'Requirement changes',
|
||||
'New deprecations',
|
||||
'Removals',
|
||||
'Features',
|
||||
'Security',
|
||||
'Bugfix',
|
||||
'Changes',
|
||||
)
|
||||
|
||||
# The maximum line length for an entry
|
||||
MAX_LINE_LENGTH = 80
|
||||
|
||||
CategoryContent = namedtuple('CategoryContent', [
|
||||
'name', 'title_line', # Title text and line number of the title
|
||||
'body', 'body_line', # Body text and starting line number of the body
|
||||
])
|
||||
|
||||
class ChangelogFormat:
|
||||
"""Virtual class documenting how to write a changelog format class."""
|
||||
|
||||
@classmethod
|
||||
def extract_top_version(cls, changelog_file_content):
|
||||
"""Split out the top version section.
|
||||
|
||||
If the top version is already released, create a new top
|
||||
version section for an unreleased version.
|
||||
|
||||
Return ``(header, top_version_title, top_version_body, trailer)``
|
||||
where the "top version" is the existing top version section if it's
|
||||
for unreleased changes, and a newly created section otherwise.
|
||||
To assemble the changelog after modifying top_version_body,
|
||||
concatenate the four pieces.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def version_title_text(cls, version_title):
|
||||
"""Return the text of a formatted version section title."""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def split_categories(cls, version_body):
|
||||
"""Split a changelog version section body into categories.
|
||||
|
||||
Return a list of `CategoryContent` the name is category title
|
||||
without any formatting.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def format_category(cls, title, body):
|
||||
"""Construct the text of a category section from its title and body."""
|
||||
raise NotImplementedError
|
||||
|
||||
class TextChangelogFormat(ChangelogFormat):
|
||||
"""The traditional Mbed TLS changelog format."""
|
||||
|
||||
_unreleased_version_text = '= {} x.x.x branch released xxxx-xx-xx'
|
||||
@classmethod
|
||||
def is_released_version(cls, title):
|
||||
# Look for an incomplete release date
|
||||
return not re.search(r'[0-9x]{4}-[0-9x]{2}-[0-9x]?x', title)
|
||||
|
||||
_top_version_re = re.compile(r'(?:\A|\n)(=[^\n]*\n+)(.*?\n)(?:=|$)',
|
||||
re.DOTALL)
|
||||
_name_re = re.compile(r'=\s(.*)\s[0-9x]+\.', re.DOTALL)
|
||||
@classmethod
|
||||
def extract_top_version(cls, changelog_file_content):
|
||||
"""A version section starts with a line starting with '='."""
|
||||
m = re.search(cls._top_version_re, changelog_file_content)
|
||||
top_version_start = m.start(1)
|
||||
top_version_end = m.end(2)
|
||||
top_version_title = m.group(1)
|
||||
top_version_body = m.group(2)
|
||||
name = re.match(cls._name_re, top_version_title).group(1)
|
||||
if cls.is_released_version(top_version_title):
|
||||
top_version_end = top_version_start
|
||||
top_version_title = cls._unreleased_version_text.format(name) + '\n\n'
|
||||
top_version_body = ''
|
||||
return (changelog_file_content[:top_version_start],
|
||||
top_version_title, top_version_body,
|
||||
changelog_file_content[top_version_end:])
|
||||
|
||||
@classmethod
|
||||
def version_title_text(cls, version_title):
|
||||
return re.sub(r'\n.*', version_title, re.DOTALL)
|
||||
|
||||
_category_title_re = re.compile(r'(^\w.*)\n+', re.MULTILINE)
|
||||
@classmethod
|
||||
def split_categories(cls, version_body):
|
||||
"""A category title is a line with the title in column 0."""
|
||||
if not version_body:
|
||||
return []
|
||||
title_matches = list(re.finditer(cls._category_title_re, version_body))
|
||||
if not title_matches or title_matches[0].start() != 0:
|
||||
# There is junk before the first category.
|
||||
raise CategoryParseError(0, 'Junk found where category expected')
|
||||
title_starts = [m.start(1) for m in title_matches]
|
||||
body_starts = [m.end(0) for m in title_matches]
|
||||
body_ends = title_starts[1:] + [len(version_body)]
|
||||
bodies = [version_body[body_start:body_end].rstrip('\n') + '\n'
|
||||
for (body_start, body_end) in zip(body_starts, body_ends)]
|
||||
title_lines = [version_body[:pos].count('\n') for pos in title_starts]
|
||||
body_lines = [version_body[:pos].count('\n') for pos in body_starts]
|
||||
return [CategoryContent(title_match.group(1), title_line,
|
||||
body, body_line)
|
||||
for title_match, title_line, body, body_line
|
||||
in zip(title_matches, title_lines, bodies, body_lines)]
|
||||
|
||||
@classmethod
|
||||
def format_category(cls, title, body):
|
||||
# `split_categories` ensures that each body ends with a newline.
|
||||
# Make sure that there is additionally a blank line between categories.
|
||||
if not body.endswith('\n\n'):
|
||||
body += '\n'
|
||||
return title + '\n' + body
|
||||
|
||||
class ChangeLog:
|
||||
"""An Mbed TLS changelog.
|
||||
|
||||
A changelog file consists of some header text followed by one or
|
||||
more version sections. The version sections are in reverse
|
||||
chronological order. Each version section consists of a title and a body.
|
||||
|
||||
The body of a version section consists of zero or more category
|
||||
subsections. Each category subsection consists of a title and a body.
|
||||
|
||||
A changelog entry file has the same format as the body of a version section.
|
||||
|
||||
A `ChangelogFormat` object defines the concrete syntax of the changelog.
|
||||
Entry files must have the same format as the changelog file.
|
||||
"""
|
||||
|
||||
# Only accept dotted version numbers (e.g. "3.1", not "3").
|
||||
# Refuse ".x" in a version number where x is a letter: this indicates
|
||||
# a version that is not yet released. Something like "3.1a" is accepted.
|
||||
_version_number_re = re.compile(r'[0-9]+\.[0-9A-Za-z.]+')
|
||||
_incomplete_version_number_re = re.compile(r'.*\.[A-Za-z]')
|
||||
_only_url_re = re.compile(r'^\s*\w+://\S+\s*$')
|
||||
_has_url_re = re.compile(r'.*://.*')
|
||||
|
||||
def add_categories_from_text(self, filename, line_offset,
|
||||
text, allow_unknown_category):
|
||||
"""Parse a version section or entry file."""
|
||||
try:
|
||||
categories = self.format.split_categories(text)
|
||||
except CategoryParseError as e:
|
||||
raise InputFormatError(filename, line_offset + e.line_offset,
|
||||
e.error_message)
|
||||
for category in categories:
|
||||
if not allow_unknown_category and \
|
||||
category.name not in self.categories:
|
||||
raise InputFormatError(filename,
|
||||
line_offset + category.title_line,
|
||||
'Unknown category: "{}"',
|
||||
category.name)
|
||||
|
||||
body_split = category.body.splitlines()
|
||||
|
||||
for line_number, line in enumerate(body_split, 1):
|
||||
if not self._only_url_re.match(line) and \
|
||||
len(line) > MAX_LINE_LENGTH:
|
||||
long_url_msg = '. URL exceeding length limit must be alone in its line.' \
|
||||
if self._has_url_re.match(line) else ""
|
||||
raise InputFormatError(filename,
|
||||
category.body_line + line_number,
|
||||
'Line is longer than allowed: '
|
||||
'Length {} (Max {}){}',
|
||||
len(line), MAX_LINE_LENGTH,
|
||||
long_url_msg)
|
||||
|
||||
self.categories[category.name] += category.body
|
||||
|
||||
def __init__(self, input_stream, changelog_format):
|
||||
"""Create a changelog object.
|
||||
|
||||
Populate the changelog object from the content of the file
|
||||
input_stream.
|
||||
"""
|
||||
self.format = changelog_format
|
||||
whole_file = input_stream.read()
|
||||
(self.header,
|
||||
self.top_version_title, top_version_body,
|
||||
self.trailer) = self.format.extract_top_version(whole_file)
|
||||
# Split the top version section into categories.
|
||||
self.categories = OrderedDict()
|
||||
for category in STANDARD_CATEGORIES:
|
||||
self.categories[category] = ''
|
||||
offset = (self.header + self.top_version_title).count('\n') + 1
|
||||
|
||||
self.add_categories_from_text(input_stream.name, offset,
|
||||
top_version_body, True)
|
||||
|
||||
def add_file(self, input_stream):
|
||||
"""Add changelog entries from a file.
|
||||
"""
|
||||
self.add_categories_from_text(input_stream.name, 1,
|
||||
input_stream.read(), False)
|
||||
|
||||
def write(self, filename):
|
||||
"""Write the changelog to the specified file.
|
||||
"""
|
||||
with open(filename, 'w', encoding='utf-8') as out:
|
||||
out.write(self.header)
|
||||
out.write(self.top_version_title)
|
||||
for title, body in self.categories.items():
|
||||
if not body:
|
||||
continue
|
||||
out.write(self.format.format_category(title, body))
|
||||
out.write(self.trailer)
|
||||
|
||||
|
||||
@functools.total_ordering
|
||||
class EntryFileSortKey:
|
||||
"""This classes defines an ordering on changelog entry files: older < newer.
|
||||
|
||||
* Merged entry files are sorted according to their merge date (date of
|
||||
the merge commit that brought the commit that created the file into
|
||||
the target branch).
|
||||
* Committed but unmerged entry files are sorted according to the date
|
||||
of the commit that adds them.
|
||||
* Uncommitted entry files are sorted according to their modification time.
|
||||
|
||||
This class assumes that the file is in a git working directory with
|
||||
the target branch checked out.
|
||||
"""
|
||||
|
||||
# Categories of files. A lower number is considered older.
|
||||
MERGED = 0
|
||||
COMMITTED = 1
|
||||
LOCAL = 2
|
||||
|
||||
@staticmethod
|
||||
def creation_hash(filename):
|
||||
"""Return the git commit id at which the given file was created.
|
||||
|
||||
Return None if the file was never checked into git.
|
||||
"""
|
||||
hashes = subprocess.check_output(['git', 'log', '--format=%H',
|
||||
'--follow',
|
||||
'--', filename])
|
||||
m = re.search('(.+)$', hashes.decode('ascii'))
|
||||
if not m:
|
||||
# The git output is empty. This means that the file was
|
||||
# never checked in.
|
||||
return None
|
||||
# The last commit in the log is the oldest one, which is when the
|
||||
# file was created.
|
||||
return m.group(0)
|
||||
|
||||
@staticmethod
|
||||
def list_merges(some_hash, target, *options):
|
||||
"""List merge commits from some_hash to target.
|
||||
|
||||
Pass options to git to select which commits are included.
|
||||
"""
|
||||
text = subprocess.check_output(['git', 'rev-list',
|
||||
'--merges', *options,
|
||||
'..'.join([some_hash, target])])
|
||||
return text.decode('ascii').rstrip('\n').split('\n')
|
||||
|
||||
@classmethod
|
||||
def merge_hash(cls, some_hash):
|
||||
"""Return the git commit id at which the given commit was merged.
|
||||
|
||||
Return None if the given commit was never merged.
|
||||
"""
|
||||
target = 'HEAD'
|
||||
# List the merges from some_hash to the target in two ways.
|
||||
# The ancestry list is the ones that are both descendants of
|
||||
# some_hash and ancestors of the target.
|
||||
ancestry = frozenset(cls.list_merges(some_hash, target,
|
||||
'--ancestry-path'))
|
||||
# The first_parents list only contains merges that are directly
|
||||
# on the target branch. We want it in reverse order (oldest first).
|
||||
first_parents = cls.list_merges(some_hash, target,
|
||||
'--first-parent', '--reverse')
|
||||
# Look for the oldest merge commit that's both on the direct path
|
||||
# and directly on the target branch. That's the place where some_hash
|
||||
# was merged on the target branch. See
|
||||
# https://stackoverflow.com/questions/8475448/find-merge-commit-which-include-a-specific-commit
|
||||
for commit in first_parents:
|
||||
if commit in ancestry:
|
||||
return commit
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def commit_timestamp(commit_id):
|
||||
"""Return the timestamp of the given commit."""
|
||||
text = subprocess.check_output(['git', 'show', '-s',
|
||||
'--format=%ct',
|
||||
commit_id])
|
||||
return datetime.datetime.utcfromtimestamp(int(text))
|
||||
|
||||
@staticmethod
|
||||
def file_timestamp(filename):
|
||||
"""Return the modification timestamp of the given file."""
|
||||
mtime = os.stat(filename).st_mtime
|
||||
return datetime.datetime.fromtimestamp(mtime)
|
||||
|
||||
def __init__(self, filename):
|
||||
"""Determine position of the file in the changelog entry order.
|
||||
|
||||
This constructor returns an object that can be used with comparison
|
||||
operators, with `sort` and `sorted`, etc. Older entries are sorted
|
||||
before newer entries.
|
||||
"""
|
||||
self.filename = filename
|
||||
creation_hash = self.creation_hash(filename)
|
||||
if not creation_hash:
|
||||
self.category = self.LOCAL
|
||||
self.datetime = self.file_timestamp(filename)
|
||||
return
|
||||
merge_hash = self.merge_hash(creation_hash)
|
||||
if not merge_hash:
|
||||
self.category = self.COMMITTED
|
||||
self.datetime = self.commit_timestamp(creation_hash)
|
||||
return
|
||||
self.category = self.MERGED
|
||||
self.datetime = self.commit_timestamp(merge_hash)
|
||||
|
||||
def sort_key(self):
|
||||
""""Return a concrete sort key for this entry file sort key object.
|
||||
|
||||
``ts1 < ts2`` is implemented as ``ts1.sort_key() < ts2.sort_key()``.
|
||||
"""
|
||||
return (self.category, self.datetime, self.filename)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.sort_key() == other.sort_key()
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.sort_key() < other.sort_key()
|
||||
|
||||
|
||||
def check_output(generated_output_file, main_input_file, merged_files):
|
||||
"""Make sanity checks on the generated output.
|
||||
|
||||
The intent of these sanity checks is to have reasonable confidence
|
||||
that no content has been lost.
|
||||
|
||||
The sanity check is that every line that is present in an input file
|
||||
is also present in an output file. This is not perfect but good enough
|
||||
for now.
|
||||
"""
|
||||
with open(generated_output_file, 'r', encoding='utf-8') as fd:
|
||||
generated_output = set(fd)
|
||||
for line in open(main_input_file, 'r', encoding='utf-8'):
|
||||
if line not in generated_output:
|
||||
raise LostContent('original file', line)
|
||||
for merged_file in merged_files:
|
||||
for line in open(merged_file, 'r', encoding='utf-8'):
|
||||
if line not in generated_output:
|
||||
raise LostContent(merged_file, line)
|
||||
|
||||
def finish_output(changelog, output_file, input_file, merged_files):
|
||||
"""Write the changelog to the output file.
|
||||
|
||||
The input file and the list of merged files are used only for sanity
|
||||
checks on the output.
|
||||
"""
|
||||
if os.path.exists(output_file) and not os.path.isfile(output_file):
|
||||
# The output is a non-regular file (e.g. pipe). Write to it directly.
|
||||
output_temp = output_file
|
||||
else:
|
||||
# The output is a regular file. Write to a temporary file,
|
||||
# then move it into place atomically.
|
||||
output_temp = output_file + '.tmp'
|
||||
changelog.write(output_temp)
|
||||
check_output(output_temp, input_file, merged_files)
|
||||
if output_temp != output_file:
|
||||
os.rename(output_temp, output_file)
|
||||
|
||||
def remove_merged_entries(files_to_remove):
|
||||
for filename in files_to_remove:
|
||||
os.remove(filename)
|
||||
|
||||
def list_files_to_merge(options):
|
||||
"""List the entry files to merge, oldest first.
|
||||
|
||||
"Oldest" is defined by `EntryFileSortKey`.
|
||||
|
||||
Also check for required .txt extension
|
||||
"""
|
||||
files_to_merge = glob.glob(os.path.join(options.dir, '*'))
|
||||
|
||||
# Ignore 00README.md
|
||||
readme = os.path.join(options.dir, "00README.md")
|
||||
if readme in files_to_merge:
|
||||
files_to_merge.remove(readme)
|
||||
|
||||
# Identify files without the required .txt extension
|
||||
bad_files = [x for x in files_to_merge if not x.endswith(".txt")]
|
||||
if bad_files:
|
||||
raise FilePathError(bad_files)
|
||||
|
||||
files_to_merge.sort(key=EntryFileSortKey)
|
||||
return files_to_merge
|
||||
|
||||
def merge_entries(options):
|
||||
"""Merge changelog entries into the changelog file.
|
||||
|
||||
Read the changelog file from options.input.
|
||||
Check that all entries have a .txt extension
|
||||
Read entries to merge from the directory options.dir.
|
||||
Write the new changelog to options.output.
|
||||
Remove the merged entries if options.keep_entries is false.
|
||||
"""
|
||||
with open(options.input, 'r', encoding='utf-8') as input_file:
|
||||
changelog = ChangeLog(input_file, TextChangelogFormat)
|
||||
files_to_merge = list_files_to_merge(options)
|
||||
if not files_to_merge:
|
||||
sys.stderr.write('There are no pending changelog entries.\n')
|
||||
return
|
||||
for filename in files_to_merge:
|
||||
with open(filename, 'r', encoding='utf-8') as input_file:
|
||||
changelog.add_file(input_file)
|
||||
finish_output(changelog, options.output, options.input, files_to_merge)
|
||||
if not options.keep_entries:
|
||||
remove_merged_entries(files_to_merge)
|
||||
|
||||
def show_file_timestamps(options):
|
||||
"""List the files to merge and their timestamp.
|
||||
|
||||
This is only intended for debugging purposes.
|
||||
"""
|
||||
files = list_files_to_merge(options)
|
||||
for filename in files:
|
||||
ts = EntryFileSortKey(filename)
|
||||
print(ts.category, ts.datetime, filename)
|
||||
|
||||
def set_defaults(options):
|
||||
"""Add default values for missing options."""
|
||||
output_file = getattr(options, 'output', None)
|
||||
if output_file is None:
|
||||
options.output = options.input
|
||||
if getattr(options, 'keep_entries', None) is None:
|
||||
options.keep_entries = (output_file is not None)
|
||||
|
||||
def main():
|
||||
"""Command line entry point."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--dir', '-d', metavar='DIR',
|
||||
default='ChangeLog.d',
|
||||
help='Directory to read entries from'
|
||||
' (default: ChangeLog.d)')
|
||||
parser.add_argument('--input', '-i', metavar='FILE',
|
||||
default='ChangeLog',
|
||||
help='Existing changelog file to read from and augment'
|
||||
' (default: ChangeLog)')
|
||||
parser.add_argument('--keep-entries',
|
||||
action='store_true', dest='keep_entries', default=None,
|
||||
help='Keep the files containing entries'
|
||||
' (default: remove them if --output/-o is not specified)')
|
||||
parser.add_argument('--no-keep-entries',
|
||||
action='store_false', dest='keep_entries',
|
||||
help='Remove the files containing entries after they are merged'
|
||||
' (default: remove them if --output/-o is not specified)')
|
||||
parser.add_argument('--output', '-o', metavar='FILE',
|
||||
help='Output changelog file'
|
||||
' (default: overwrite the input)')
|
||||
parser.add_argument('--list-files-only',
|
||||
action='store_true',
|
||||
help=('Only list the files that would be processed '
|
||||
'(with some debugging information)'))
|
||||
options = parser.parse_args()
|
||||
set_defaults(options)
|
||||
if options.list_files_only:
|
||||
show_file_timestamps(options)
|
||||
return
|
||||
merge_entries(options)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,5 +0,0 @@
|
||||
# Python modules required to build Mbed TLS in ordinary conditions.
|
||||
|
||||
# Required to (re-)generate source files. Not needed if the generated source
|
||||
# files are already present and up-to-date.
|
||||
-r driver.requirements.txt
|
||||
@@ -1,148 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
#
|
||||
# Purpose
|
||||
#
|
||||
# Sets the version numbers in the source code to those given.
|
||||
#
|
||||
# Usage: bump_version.sh [ --version <version> ] [ --so-crypto <version>]
|
||||
# [ --so-x509 <version> ] [ --so-tls <version> ]
|
||||
# [ -v | --verbose ] [ -h | --help ]
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=""
|
||||
SOVERSION=""
|
||||
|
||||
# Parse arguments
|
||||
#
|
||||
until [ -z "$1" ]
|
||||
do
|
||||
case "$1" in
|
||||
--version)
|
||||
# Version to use
|
||||
shift
|
||||
VERSION=$1
|
||||
;;
|
||||
--so-crypto)
|
||||
shift
|
||||
SO_CRYPTO=$1
|
||||
;;
|
||||
--so-x509)
|
||||
shift
|
||||
SO_X509=$1
|
||||
;;
|
||||
--so-tls)
|
||||
shift
|
||||
SO_TLS=$1
|
||||
;;
|
||||
-v|--verbose)
|
||||
# Be verbose
|
||||
VERBOSE="1"
|
||||
;;
|
||||
-h|--help)
|
||||
# print help
|
||||
echo "Usage: $0"
|
||||
echo -e " -h|--help\t\tPrint this help."
|
||||
echo -e " --version <version>\tVersion to bump to."
|
||||
echo -e " --so-crypto <version>\tSO version to bump libmbedcrypto to."
|
||||
echo -e " --so-x509 <version>\tSO version to bump libmbedx509 to."
|
||||
echo -e " --so-tls <version>\tSO version to bump libmbedtls to."
|
||||
echo -e " -v|--verbose\t\tVerbose."
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
# print error
|
||||
echo "Unknown argument: '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "X" = "X$VERSION" ];
|
||||
then
|
||||
echo "No version specified. Unable to continue."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping VERSION in CMakeLists.txt"
|
||||
sed -e "s/ VERSION [0-9.]\{1,\}/ VERSION $VERSION/g" < CMakeLists.txt > tmp
|
||||
mv tmp CMakeLists.txt
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping VERSION in library/CMakeLists.txt"
|
||||
sed -e "s/ VERSION [0-9.]\{1,\}/ VERSION $VERSION/g" < library/CMakeLists.txt > tmp
|
||||
mv tmp library/CMakeLists.txt
|
||||
|
||||
if [ "X" != "X$SO_CRYPTO" ];
|
||||
then
|
||||
[ $VERBOSE ] && echo "Bumping SOVERSION for libmbedcrypto in library/CMakeLists.txt"
|
||||
sed -e "/mbedcrypto/ s/ SOVERSION [0-9]\{1,\}/ SOVERSION $SO_CRYPTO/g" < library/CMakeLists.txt > tmp
|
||||
mv tmp library/CMakeLists.txt
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping SOVERSION for libmbedcrypto in library/Makefile"
|
||||
sed -e "s/SOEXT_CRYPTO?=so.[0-9]\{1,\}/SOEXT_CRYPTO?=so.$SO_CRYPTO/g" < library/Makefile > tmp
|
||||
mv tmp library/Makefile
|
||||
fi
|
||||
|
||||
if [ "X" != "X$SO_X509" ];
|
||||
then
|
||||
[ $VERBOSE ] && echo "Bumping SOVERSION for libmbedx509 in library/CMakeLists.txt"
|
||||
sed -e "/mbedx509/ s/ SOVERSION [0-9]\{1,\}/ SOVERSION $SO_X509/g" < library/CMakeLists.txt > tmp
|
||||
mv tmp library/CMakeLists.txt
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping SOVERSION for libmbedx509 in library/Makefile"
|
||||
sed -e "s/SOEXT_X509?=so.[0-9]\{1,\}/SOEXT_X509?=so.$SO_X509/g" < library/Makefile > tmp
|
||||
mv tmp library/Makefile
|
||||
fi
|
||||
|
||||
if [ "X" != "X$SO_TLS" ];
|
||||
then
|
||||
[ $VERBOSE ] && echo "Bumping SOVERSION for libmbedtls in library/CMakeLists.txt"
|
||||
sed -e "/mbedtls/ s/ SOVERSION [0-9]\{1,\}/ SOVERSION $SO_TLS/g" < library/CMakeLists.txt > tmp
|
||||
mv tmp library/CMakeLists.txt
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping SOVERSION for libmbedtls in library/Makefile"
|
||||
sed -e "s/SOEXT_TLS?=so.[0-9]\{1,\}/SOEXT_TLS?=so.$SO_TLS/g" < library/Makefile > tmp
|
||||
mv tmp library/Makefile
|
||||
fi
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping VERSION in include/mbedtls/build_info.h"
|
||||
read MAJOR MINOR PATCH <<<$(IFS="."; echo $VERSION)
|
||||
VERSION_NR="$( printf "0x%02X%02X%02X00" $MAJOR $MINOR $PATCH )"
|
||||
cat include/mbedtls/build_info.h | \
|
||||
sed -e "s/\(# *define *[A-Z]*_VERSION\)_MAJOR .\{1,\}/\1_MAJOR $MAJOR/" | \
|
||||
sed -e "s/\(# *define *[A-Z]*_VERSION\)_MINOR .\{1,\}/\1_MINOR $MINOR/" | \
|
||||
sed -e "s/\(# *define *[A-Z]*_VERSION\)_PATCH .\{1,\}/\1_PATCH $PATCH/" | \
|
||||
sed -e "s/\(# *define *[A-Z]*_VERSION\)_NUMBER .\{1,\}/\1_NUMBER $VERSION_NR/" | \
|
||||
sed -e "s/\(# *define *[A-Z]*_VERSION\)_STRING .\{1,\}/\1_STRING \"$VERSION\"/" | \
|
||||
sed -e "s/\(# *define *[A-Z]*_VERSION\)_STRING_FULL .\{1,\}/\1_STRING_FULL \"Mbed TLS $VERSION\"/" \
|
||||
> tmp
|
||||
mv tmp include/mbedtls/build_info.h
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping version in tests/suites/test_suite_version.data"
|
||||
sed -e "s/version:\".\{1,\}/version:\"$VERSION\"/g" < tf-psa-crypto/tests/suites/test_suite_version.data > tmp
|
||||
mv tmp tf-psa-crypto/tests/suites/test_suite_version.data
|
||||
|
||||
[ $VERBOSE ] && echo "Bumping PROJECT_NAME in doxygen/mbedtls.doxyfile and doxygen/input/doc_mainpage.h"
|
||||
for i in doxygen/mbedtls.doxyfile doxygen/input/doc_mainpage.h;
|
||||
do
|
||||
sed -e "s/\\([Mm]bed TLS v\\)[0-9][0-9.]*/\\1$VERSION/g" < $i > tmp
|
||||
mv tmp $i
|
||||
done
|
||||
|
||||
[ $VERBOSE ] && echo "Re-generating library/error.c"
|
||||
scripts/generate_errors.pl
|
||||
|
||||
[ $VERBOSE ] && echo "Re-generating programs/test/query_config.c"
|
||||
scripts/generate_query_config.pl
|
||||
|
||||
[ $VERBOSE ] && echo "Re-generating library/version_features.c"
|
||||
scripts/generate_features.pl
|
||||
|
||||
[ $VERBOSE ] && echo "Re-generating visualc files"
|
||||
scripts/generate_visualc_files.pl
|
||||
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Sanity checks for test data.
|
||||
|
||||
This program contains a class for traversing test cases that can be used
|
||||
independently of the checks.
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
import scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import collect_test_cases
|
||||
|
||||
|
||||
class DescriptionChecker(collect_test_cases.TestDescriptionExplorer):
|
||||
"""Check all test case descriptions.
|
||||
|
||||
* Check that each description is valid (length, allowed character set, etc.).
|
||||
* Check that there is no duplicated description inside of one test suite.
|
||||
"""
|
||||
|
||||
def __init__(self, results):
|
||||
self.results = results
|
||||
|
||||
def new_per_file_state(self):
|
||||
"""Dictionary mapping descriptions to their line number."""
|
||||
return {}
|
||||
|
||||
def process_test_case(self, per_file_state,
|
||||
file_name, line_number, description):
|
||||
"""Check test case descriptions for errors."""
|
||||
results = self.results
|
||||
seen = per_file_state
|
||||
if description in seen:
|
||||
results.error(file_name, line_number,
|
||||
'Duplicate description (also line {})',
|
||||
seen[description])
|
||||
return
|
||||
if re.search(br'[\t;]', description):
|
||||
results.error(file_name, line_number,
|
||||
'Forbidden character \'{}\' in description',
|
||||
re.search(br'[\t;]', description).group(0).decode('ascii'))
|
||||
if re.search(br'[^ -~]', description):
|
||||
results.error(file_name, line_number,
|
||||
'Non-ASCII character in description')
|
||||
if len(description) > 66:
|
||||
results.warning(file_name, line_number,
|
||||
'Test description too long ({} > 66)',
|
||||
len(description))
|
||||
seen[description] = line_number
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--list-all',
|
||||
action='store_true',
|
||||
help='List all test cases, without doing checks')
|
||||
parser.add_argument('--quiet', '-q',
|
||||
action='store_true',
|
||||
help='Hide warnings')
|
||||
parser.add_argument('--verbose', '-v',
|
||||
action='store_false', dest='quiet',
|
||||
help='Show warnings (default: on; undoes --quiet)')
|
||||
options = parser.parse_args()
|
||||
if options.list_all:
|
||||
descriptions = collect_test_cases.collect_available_test_cases()
|
||||
sys.stdout.write('\n'.join(descriptions + ['']))
|
||||
return
|
||||
results = collect_test_cases.Results(options)
|
||||
checker = DescriptionChecker(results)
|
||||
try:
|
||||
checker.walk_all()
|
||||
except collect_test_cases.ScriptOutputError as e:
|
||||
results.error(e.script_name, e.idx,
|
||||
'"{}" should be listed as "<suite_name>;<description>"',
|
||||
e.line)
|
||||
if (results.warnings or results.errors) and not options.quiet:
|
||||
sys.stderr.write('{}: {} errors, {} warnings\n'
|
||||
.format(sys.argv[0], results.errors, results.warnings))
|
||||
sys.exit(1 if results.errors else 0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,28 +0,0 @@
|
||||
# Python package requirements for Mbed TLS testing.
|
||||
|
||||
-r driver.requirements.txt
|
||||
|
||||
# Use a known version of Pylint, because new versions tend to add warnings
|
||||
# that could start rejecting our code.
|
||||
# 2.4.4 is the version in Ubuntu 20.04. It supports Python >=3.5.
|
||||
pylint == 2.4.4
|
||||
|
||||
# Use a version of mypy that is compatible with our code base.
|
||||
# mypy <0.940 is known not to work: see commit
|
||||
# :/Upgrade mypy to the last version supporting Python 3.6
|
||||
# mypy >=0.960 is known not to work:
|
||||
# https://github.com/Mbed-TLS/mbedtls-framework/issues/50
|
||||
# mypy 0.942 is the version in Ubuntu 22.04.
|
||||
mypy == 0.942
|
||||
|
||||
# At the time of writing, only needed for tests/scripts/audit-validity-dates.py.
|
||||
# It needs >=35.0.0 for correct operation, and that requires Python >=3.6,
|
||||
# but our CI has Python 3.5. So let pip install the newest version that's
|
||||
# compatible with the running Python: this way we get something good enough
|
||||
# for mypy and pylint under Python 3.5, and we also get something good enough
|
||||
# to run audit-validity-dates.py on Python >=3.6.
|
||||
cryptography # >= 35.0.0
|
||||
|
||||
# For building `framework/data_files/server9-bad-saltlen.crt` and check python
|
||||
# files.
|
||||
asn1crypto
|
||||
@@ -1,953 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
This script is for comparing the size of the library files from two
|
||||
different Git revisions within an Mbed TLS repository.
|
||||
The results of the comparison is formatted as csv and stored at a
|
||||
configurable location.
|
||||
Note: must be run from Mbed TLS root.
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import typing
|
||||
from enum import Enum
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import build_tree
|
||||
from mbedtls_framework import logging_util
|
||||
from mbedtls_framework import typing_util
|
||||
|
||||
class SupportedArch(Enum):
|
||||
"""Supported architecture for code size measurement."""
|
||||
AARCH64 = 'aarch64'
|
||||
AARCH32 = 'aarch32'
|
||||
ARMV8_M = 'armv8-m'
|
||||
X86_64 = 'x86_64'
|
||||
X86 = 'x86'
|
||||
|
||||
|
||||
class SupportedConfig(Enum):
|
||||
"""Supported configuration for code size measurement."""
|
||||
DEFAULT = 'default'
|
||||
TFM_MEDIUM = 'tfm-medium'
|
||||
|
||||
|
||||
# Static library
|
||||
MBEDTLS_STATIC_LIB = {
|
||||
'CRYPTO': 'library/libmbedcrypto.a',
|
||||
'X509': 'library/libmbedx509.a',
|
||||
'TLS': 'library/libmbedtls.a',
|
||||
}
|
||||
|
||||
class CodeSizeDistinctInfo: # pylint: disable=too-few-public-methods
|
||||
"""Data structure to store possibly distinct information for code size
|
||||
comparison."""
|
||||
def __init__( #pylint: disable=too-many-arguments
|
||||
self,
|
||||
version: str,
|
||||
git_rev: str,
|
||||
arch: str,
|
||||
config: str,
|
||||
compiler: str,
|
||||
opt_level: str,
|
||||
) -> None:
|
||||
"""
|
||||
:param: version: which version to compare with for code size.
|
||||
:param: git_rev: Git revision to calculate code size.
|
||||
:param: arch: architecture to measure code size on.
|
||||
:param: config: Configuration type to calculate code size.
|
||||
(See SupportedConfig)
|
||||
:param: compiler: compiler used to build library/*.o.
|
||||
:param: opt_level: Options that control optimization. (E.g. -Os)
|
||||
"""
|
||||
self.version = version
|
||||
self.git_rev = git_rev
|
||||
self.arch = arch
|
||||
self.config = config
|
||||
self.compiler = compiler
|
||||
self.opt_level = opt_level
|
||||
# Note: Variables below are not initialized by class instantiation.
|
||||
self.pre_make_cmd = [] #type: typing.List[str]
|
||||
self.make_cmd = ''
|
||||
|
||||
def get_info_indication(self):
|
||||
"""Return a unique string to indicate Code Size Distinct Information."""
|
||||
return '{git_rev}-{arch}-{config}-{compiler}'.format(**self.__dict__)
|
||||
|
||||
|
||||
class CodeSizeCommonInfo: # pylint: disable=too-few-public-methods
|
||||
"""Data structure to store common information for code size comparison."""
|
||||
def __init__(
|
||||
self,
|
||||
host_arch: str,
|
||||
measure_cmd: str,
|
||||
) -> None:
|
||||
"""
|
||||
:param host_arch: host architecture.
|
||||
:param measure_cmd: command to measure code size for library/*.o.
|
||||
"""
|
||||
self.host_arch = host_arch
|
||||
self.measure_cmd = measure_cmd
|
||||
|
||||
def get_info_indication(self):
|
||||
"""Return a unique string to indicate Code Size Common Information."""
|
||||
return '{measure_tool}'\
|
||||
.format(measure_tool=self.measure_cmd.strip().split(' ')[0])
|
||||
|
||||
class CodeSizeResultInfo: # pylint: disable=too-few-public-methods
|
||||
"""Data structure to store result options for code size comparison."""
|
||||
def __init__( #pylint: disable=too-many-arguments
|
||||
self,
|
||||
record_dir: str,
|
||||
comp_dir: str,
|
||||
with_markdown=False,
|
||||
stdout=False,
|
||||
show_all=False,
|
||||
) -> None:
|
||||
"""
|
||||
:param record_dir: directory to store code size record.
|
||||
:param comp_dir: directory to store results of code size comparision.
|
||||
:param with_markdown: write comparision result into a markdown table.
|
||||
(Default: False)
|
||||
:param stdout: direct comparison result into sys.stdout.
|
||||
(Default False)
|
||||
:param show_all: show all objects in comparison result. (Default False)
|
||||
"""
|
||||
self.record_dir = record_dir
|
||||
self.comp_dir = comp_dir
|
||||
self.with_markdown = with_markdown
|
||||
self.stdout = stdout
|
||||
self.show_all = show_all
|
||||
|
||||
|
||||
DETECT_ARCH_CMD = "cc -dM -E - < /dev/null"
|
||||
def detect_arch() -> str:
|
||||
"""Auto-detect host architecture."""
|
||||
cc_output = subprocess.check_output(DETECT_ARCH_CMD, shell=True).decode()
|
||||
if '__aarch64__' in cc_output:
|
||||
return SupportedArch.AARCH64.value
|
||||
if '__arm__' in cc_output:
|
||||
return SupportedArch.AARCH32.value
|
||||
if '__x86_64__' in cc_output:
|
||||
return SupportedArch.X86_64.value
|
||||
if '__i386__' in cc_output:
|
||||
return SupportedArch.X86.value
|
||||
else:
|
||||
print("Unknown host architecture, cannot auto-detect arch.")
|
||||
sys.exit(1)
|
||||
|
||||
TFM_MEDIUM_CONFIG_H = 'configs/ext/tfm_mbedcrypto_config_profile_medium.h'
|
||||
TFM_MEDIUM_CRYPTO_CONFIG_H = 'configs/ext/crypto_config_profile_medium.h'
|
||||
|
||||
CONFIG_H = 'include/mbedtls/mbedtls_config.h'
|
||||
CRYPTO_CONFIG_H = 'tf-psa-crypto/include/psa/crypto_config.h'
|
||||
BACKUP_SUFFIX = '.code_size.bak'
|
||||
|
||||
class CodeSizeBuildInfo: # pylint: disable=too-few-public-methods
|
||||
"""Gather information used to measure code size.
|
||||
|
||||
It collects information about architecture, configuration in order to
|
||||
infer build command for code size measurement.
|
||||
"""
|
||||
|
||||
SupportedArchConfig = [
|
||||
'-a ' + SupportedArch.AARCH64.value + ' -c ' + SupportedConfig.DEFAULT.value,
|
||||
'-a ' + SupportedArch.AARCH32.value + ' -c ' + SupportedConfig.DEFAULT.value,
|
||||
'-a ' + SupportedArch.X86_64.value + ' -c ' + SupportedConfig.DEFAULT.value,
|
||||
'-a ' + SupportedArch.X86.value + ' -c ' + SupportedConfig.DEFAULT.value,
|
||||
'-a ' + SupportedArch.ARMV8_M.value + ' -c ' + SupportedConfig.TFM_MEDIUM.value,
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
size_dist_info: CodeSizeDistinctInfo,
|
||||
host_arch: str,
|
||||
logger: logging.Logger,
|
||||
) -> None:
|
||||
"""
|
||||
:param size_dist_info:
|
||||
CodeSizeDistinctInfo containing info for code size measurement.
|
||||
- size_dist_info.arch: architecture to measure code size on.
|
||||
- size_dist_info.config: configuration type to measure
|
||||
code size with.
|
||||
- size_dist_info.compiler: compiler used to build library/*.o.
|
||||
- size_dist_info.opt_level: Options that control optimization.
|
||||
(E.g. -Os)
|
||||
:param host_arch: host architecture.
|
||||
:param logger: logging module
|
||||
"""
|
||||
self.arch = size_dist_info.arch
|
||||
self.config = size_dist_info.config
|
||||
self.compiler = size_dist_info.compiler
|
||||
self.opt_level = size_dist_info.opt_level
|
||||
|
||||
self.make_cmd = ['make', '-j', 'lib']
|
||||
|
||||
self.host_arch = host_arch
|
||||
self.logger = logger
|
||||
|
||||
def check_correctness(self) -> bool:
|
||||
"""Check whether we are using proper / supported combination
|
||||
of information to build library/*.o."""
|
||||
|
||||
# default config
|
||||
if self.config == SupportedConfig.DEFAULT.value and \
|
||||
self.arch == self.host_arch:
|
||||
return True
|
||||
# TF-M
|
||||
elif self.arch == SupportedArch.ARMV8_M.value and \
|
||||
self.config == SupportedConfig.TFM_MEDIUM.value:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def infer_pre_make_command(self) -> typing.List[str]:
|
||||
"""Infer command to set up proper configuration before running make."""
|
||||
pre_make_cmd = [] #type: typing.List[str]
|
||||
if self.config == SupportedConfig.TFM_MEDIUM.value:
|
||||
pre_make_cmd.append('cp {src} {dest}'
|
||||
.format(src=TFM_MEDIUM_CONFIG_H, dest=CONFIG_H))
|
||||
pre_make_cmd.append('cp {src} {dest}'
|
||||
.format(src=TFM_MEDIUM_CRYPTO_CONFIG_H,
|
||||
dest=CRYPTO_CONFIG_H))
|
||||
|
||||
return pre_make_cmd
|
||||
|
||||
def infer_make_cflags(self) -> str:
|
||||
"""Infer CFLAGS by instance attributes in CodeSizeDistinctInfo."""
|
||||
cflags = [] #type: typing.List[str]
|
||||
|
||||
# set optimization level
|
||||
cflags.append(self.opt_level)
|
||||
# set compiler by config
|
||||
if self.config == SupportedConfig.TFM_MEDIUM.value:
|
||||
self.compiler = 'armclang'
|
||||
cflags.append('-mcpu=cortex-m33')
|
||||
# set target
|
||||
if self.compiler == 'armclang':
|
||||
cflags.append('--target=arm-arm-none-eabi')
|
||||
|
||||
return ' '.join(cflags)
|
||||
|
||||
def infer_make_command(self) -> str:
|
||||
"""Infer make command by CFLAGS and CC."""
|
||||
|
||||
if self.check_correctness():
|
||||
# set CFLAGS=
|
||||
self.make_cmd.append('CFLAGS=\'{}\''.format(self.infer_make_cflags()))
|
||||
# set CC=
|
||||
self.make_cmd.append('CC={}'.format(self.compiler))
|
||||
return ' '.join(self.make_cmd)
|
||||
else:
|
||||
self.logger.error("Unsupported combination of architecture: {} " \
|
||||
"and configuration: {}.\n"
|
||||
.format(self.arch,
|
||||
self.config))
|
||||
self.logger.error("Please use supported combination of " \
|
||||
"architecture and configuration:")
|
||||
for comb in CodeSizeBuildInfo.SupportedArchConfig:
|
||||
self.logger.error(comb)
|
||||
self.logger.error("")
|
||||
self.logger.error("For your system, please use:")
|
||||
for comb in CodeSizeBuildInfo.SupportedArchConfig:
|
||||
if "default" in comb and self.host_arch not in comb:
|
||||
continue
|
||||
self.logger.error(comb)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class CodeSizeCalculator:
|
||||
""" A calculator to calculate code size of library/*.o based on
|
||||
Git revision and code size measurement tool.
|
||||
"""
|
||||
|
||||
def __init__( #pylint: disable=too-many-arguments
|
||||
self,
|
||||
git_rev: str,
|
||||
pre_make_cmd: typing.List[str],
|
||||
make_cmd: str,
|
||||
measure_cmd: str,
|
||||
logger: logging.Logger,
|
||||
) -> None:
|
||||
"""
|
||||
:param git_rev: Git revision. (E.g: commit)
|
||||
:param pre_make_cmd: command to set up proper config before running make.
|
||||
:param make_cmd: command to build library/*.o.
|
||||
:param measure_cmd: command to measure code size for library/*.o.
|
||||
:param logger: logging module
|
||||
"""
|
||||
self.repo_path = "."
|
||||
self.git_command = "git"
|
||||
self.make_clean = 'make clean'
|
||||
|
||||
self.git_rev = git_rev
|
||||
self.pre_make_cmd = pre_make_cmd
|
||||
self.make_cmd = make_cmd
|
||||
self.measure_cmd = measure_cmd
|
||||
self.logger = logger
|
||||
|
||||
@staticmethod
|
||||
def validate_git_revision(git_rev: str) -> str:
|
||||
result = subprocess.check_output(["git", "rev-parse", "--verify",
|
||||
git_rev + "^{commit}"],
|
||||
shell=False, universal_newlines=True)
|
||||
return result[:7]
|
||||
|
||||
def _create_git_worktree(self) -> str:
|
||||
"""Create a separate worktree for Git revision.
|
||||
If Git revision is current, use current worktree instead."""
|
||||
|
||||
if self.git_rev == 'current':
|
||||
self.logger.debug("Using current work directory.")
|
||||
git_worktree_path = self.repo_path
|
||||
else:
|
||||
self.logger.debug("Creating git worktree for {}."
|
||||
.format(self.git_rev))
|
||||
git_worktree_path = os.path.join(self.repo_path,
|
||||
"temp-" + self.git_rev)
|
||||
subprocess.check_output(
|
||||
[self.git_command, "worktree", "add", "--detach",
|
||||
git_worktree_path, self.git_rev], cwd=self.repo_path,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
|
||||
return git_worktree_path
|
||||
|
||||
@staticmethod
|
||||
def backup_config_files(restore: bool) -> None:
|
||||
"""Backup / Restore config files."""
|
||||
if restore:
|
||||
shutil.move(CONFIG_H + BACKUP_SUFFIX, CONFIG_H)
|
||||
shutil.move(CRYPTO_CONFIG_H + BACKUP_SUFFIX, CRYPTO_CONFIG_H)
|
||||
else:
|
||||
shutil.copy(CONFIG_H, CONFIG_H + BACKUP_SUFFIX)
|
||||
shutil.copy(CRYPTO_CONFIG_H, CRYPTO_CONFIG_H + BACKUP_SUFFIX)
|
||||
|
||||
def _build_libraries(self, git_worktree_path: str) -> None:
|
||||
"""Build library/*.o in the specified worktree."""
|
||||
|
||||
self.logger.debug("Building library/*.o for {}."
|
||||
.format(self.git_rev))
|
||||
my_environment = os.environ.copy()
|
||||
try:
|
||||
if self.git_rev == 'current':
|
||||
self.backup_config_files(restore=False)
|
||||
for pre_cmd in self.pre_make_cmd:
|
||||
subprocess.check_output(
|
||||
pre_cmd, env=my_environment, shell=True,
|
||||
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
||||
universal_newlines=True
|
||||
)
|
||||
subprocess.check_output(
|
||||
self.make_clean, env=my_environment, shell=True,
|
||||
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
||||
universal_newlines=True
|
||||
)
|
||||
subprocess.check_output(
|
||||
self.make_cmd, env=my_environment, shell=True,
|
||||
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
||||
universal_newlines=True
|
||||
)
|
||||
if self.git_rev == 'current':
|
||||
self.backup_config_files(restore=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self._handle_called_process_error(e, git_worktree_path)
|
||||
|
||||
def _gen_raw_code_size(self, git_worktree_path: str) -> typing.Dict[str, str]:
|
||||
"""Measure code size by a tool and return in UTF-8 encoding."""
|
||||
|
||||
self.logger.debug("Measuring code size for {} by `{}`."
|
||||
.format(self.git_rev,
|
||||
self.measure_cmd.strip().split(' ')[0]))
|
||||
|
||||
res = {}
|
||||
for mod, st_lib in MBEDTLS_STATIC_LIB.items():
|
||||
try:
|
||||
result = subprocess.check_output(
|
||||
[self.measure_cmd + ' ' + st_lib], cwd=git_worktree_path,
|
||||
shell=True, universal_newlines=True
|
||||
)
|
||||
res[mod] = result
|
||||
except subprocess.CalledProcessError as e:
|
||||
self._handle_called_process_error(e, git_worktree_path)
|
||||
|
||||
return res
|
||||
|
||||
def _remove_worktree(self, git_worktree_path: str) -> None:
|
||||
"""Remove temporary worktree."""
|
||||
if git_worktree_path != self.repo_path:
|
||||
self.logger.debug("Removing temporary worktree {}."
|
||||
.format(git_worktree_path))
|
||||
subprocess.check_output(
|
||||
[self.git_command, "worktree", "remove", "--force",
|
||||
git_worktree_path], cwd=self.repo_path,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
|
||||
def _handle_called_process_error(self, e: subprocess.CalledProcessError,
|
||||
git_worktree_path: str) -> None:
|
||||
"""Handle a CalledProcessError and quit the program gracefully.
|
||||
Remove any extra worktrees so that the script may be called again."""
|
||||
|
||||
# Tell the user what went wrong
|
||||
self.logger.error(e, exc_info=True)
|
||||
self.logger.error("Process output:\n {}".format(e.output))
|
||||
|
||||
# Quit gracefully by removing the existing worktree
|
||||
self._remove_worktree(git_worktree_path)
|
||||
sys.exit(-1)
|
||||
|
||||
def cal_libraries_code_size(self) -> typing.Dict[str, str]:
|
||||
"""Do a complete round to calculate code size of library/*.o
|
||||
by measurement tool.
|
||||
|
||||
:return A dictionary of measured code size
|
||||
- typing.Dict[mod: str]
|
||||
"""
|
||||
|
||||
git_worktree_path = self._create_git_worktree()
|
||||
try:
|
||||
self._build_libraries(git_worktree_path)
|
||||
res = self._gen_raw_code_size(git_worktree_path)
|
||||
finally:
|
||||
self._remove_worktree(git_worktree_path)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class CodeSizeGenerator:
|
||||
""" A generator based on size measurement tool for library/*.o.
|
||||
|
||||
This is an abstract class. To use it, derive a class that implements
|
||||
write_record and write_comparison methods, then call both of them with
|
||||
proper arguments.
|
||||
"""
|
||||
def __init__(self, logger: logging.Logger) -> None:
|
||||
"""
|
||||
:param logger: logging module
|
||||
"""
|
||||
self.logger = logger
|
||||
|
||||
def write_record(
|
||||
self,
|
||||
git_rev: str,
|
||||
code_size_text: typing.Dict[str, str],
|
||||
output: typing_util.Writable
|
||||
) -> None:
|
||||
"""Write size record into a file.
|
||||
|
||||
:param git_rev: Git revision. (E.g: commit)
|
||||
:param code_size_text:
|
||||
string output (utf-8) from measurement tool of code size.
|
||||
- typing.Dict[mod: str]
|
||||
:param output: output stream which the code size record is written to.
|
||||
(Note: Normally write code size record into File)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def write_comparison( #pylint: disable=too-many-arguments
|
||||
self,
|
||||
old_rev: str,
|
||||
new_rev: str,
|
||||
output: typing_util.Writable,
|
||||
with_markdown=False,
|
||||
show_all=False
|
||||
) -> None:
|
||||
"""Write a comparision result into a stream between two Git revisions.
|
||||
|
||||
:param old_rev: old Git revision to compared with.
|
||||
:param new_rev: new Git revision to compared with.
|
||||
:param output: output stream which the code size record is written to.
|
||||
(File / sys.stdout)
|
||||
:param with_markdown: write comparision result in a markdown table.
|
||||
(Default: False)
|
||||
:param show_all: show all objects in comparison result. (Default False)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class CodeSizeGeneratorWithSize(CodeSizeGenerator):
|
||||
"""Code Size Base Class for size record saving and writing."""
|
||||
|
||||
class SizeEntry: # pylint: disable=too-few-public-methods
|
||||
"""Data Structure to only store information of code size."""
|
||||
def __init__(self, text: int, data: int, bss: int, dec: int):
|
||||
self.text = text
|
||||
self.data = data
|
||||
self.bss = bss
|
||||
self.total = dec # total <=> dec
|
||||
|
||||
def __init__(self, logger: logging.Logger) -> None:
|
||||
""" Variable code_size is used to store size info for any Git revisions.
|
||||
:param code_size:
|
||||
Data Format as following:
|
||||
code_size = {
|
||||
git_rev: {
|
||||
module: {
|
||||
file_name: SizeEntry,
|
||||
...
|
||||
},
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
"""
|
||||
super().__init__(logger)
|
||||
self.code_size = {} #type: typing.Dict[str, typing.Dict]
|
||||
self.mod_total_suffix = '-' + 'TOTALS'
|
||||
|
||||
def _set_size_record(self, git_rev: str, mod: str, size_text: str) -> None:
|
||||
"""Store size information for target Git revision and high-level module.
|
||||
|
||||
size_text Format: text data bss dec hex filename
|
||||
"""
|
||||
size_record = {}
|
||||
for line in size_text.splitlines()[1:]:
|
||||
data = line.split()
|
||||
if re.match(r'\s*\(TOTALS\)', data[5]):
|
||||
data[5] = mod + self.mod_total_suffix
|
||||
# file_name: SizeEntry(text, data, bss, dec)
|
||||
size_record[data[5]] = CodeSizeGeneratorWithSize.SizeEntry(
|
||||
int(data[0]), int(data[1]), int(data[2]), int(data[3]))
|
||||
self.code_size.setdefault(git_rev, {}).update({mod: size_record})
|
||||
|
||||
def read_size_record(self, git_rev: str, fname: str) -> None:
|
||||
"""Read size information from csv file and write it into code_size.
|
||||
|
||||
fname Format: filename text data bss dec
|
||||
"""
|
||||
mod = ""
|
||||
size_record = {}
|
||||
with open(fname, 'r') as csv_file:
|
||||
for line in csv_file:
|
||||
data = line.strip().split()
|
||||
# check if we find the beginning of a module
|
||||
if data and data[0] in MBEDTLS_STATIC_LIB:
|
||||
mod = data[0]
|
||||
continue
|
||||
|
||||
if mod:
|
||||
# file_name: SizeEntry(text, data, bss, dec)
|
||||
size_record[data[0]] = CodeSizeGeneratorWithSize.SizeEntry(
|
||||
int(data[1]), int(data[2]), int(data[3]), int(data[4]))
|
||||
|
||||
# check if we hit record for the end of a module
|
||||
m = re.match(r'\w+' + self.mod_total_suffix, line)
|
||||
if m:
|
||||
if git_rev in self.code_size:
|
||||
self.code_size[git_rev].update({mod: size_record})
|
||||
else:
|
||||
self.code_size[git_rev] = {mod: size_record}
|
||||
mod = ""
|
||||
size_record = {}
|
||||
|
||||
def write_record(
|
||||
self,
|
||||
git_rev: str,
|
||||
code_size_text: typing.Dict[str, str],
|
||||
output: typing_util.Writable
|
||||
) -> None:
|
||||
"""Write size information to a file.
|
||||
|
||||
Writing Format: filename text data bss total(dec)
|
||||
"""
|
||||
for mod, size_text in code_size_text.items():
|
||||
self._set_size_record(git_rev, mod, size_text)
|
||||
|
||||
format_string = "{:<30} {:>7} {:>7} {:>7} {:>7}\n"
|
||||
output.write(format_string.format("filename",
|
||||
"text", "data", "bss", "total"))
|
||||
|
||||
for mod, f_size in self.code_size[git_rev].items():
|
||||
output.write("\n" + mod + "\n")
|
||||
for fname, size_entry in f_size.items():
|
||||
output.write(format_string
|
||||
.format(fname,
|
||||
size_entry.text, size_entry.data,
|
||||
size_entry.bss, size_entry.total))
|
||||
|
||||
def write_comparison( #pylint: disable=too-many-arguments
|
||||
self,
|
||||
old_rev: str,
|
||||
new_rev: str,
|
||||
output: typing_util.Writable,
|
||||
with_markdown=False,
|
||||
show_all=False
|
||||
) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
"""Write comparison result into a file.
|
||||
|
||||
Writing Format:
|
||||
Markdown Output:
|
||||
filename new(text) new(data) change(text) change(data)
|
||||
CSV Output:
|
||||
filename new(text) new(data) old(text) old(data) change(text) change(data)
|
||||
"""
|
||||
header_line = ["filename", "new(text)", "old(text)", "change(text)",
|
||||
"new(data)", "old(data)", "change(data)"]
|
||||
if with_markdown:
|
||||
dash_line = [":----", "----:", "----:", "----:",
|
||||
"----:", "----:", "----:"]
|
||||
# | filename | new(text) | new(data) | change(text) | change(data) |
|
||||
line_format = "| {0:<30} | {1:>9} | {4:>9} | {3:>12} | {6:>12} |\n"
|
||||
bold_text = lambda x: '**' + str(x) + '**'
|
||||
else:
|
||||
# filename new(text) new(data) old(text) old(data) change(text) change(data)
|
||||
line_format = "{0:<30} {1:>9} {4:>9} {2:>10} {5:>10} {3:>12} {6:>12}\n"
|
||||
|
||||
def cal_sect_change(
|
||||
old_size: typing.Optional[CodeSizeGeneratorWithSize.SizeEntry],
|
||||
new_size: typing.Optional[CodeSizeGeneratorWithSize.SizeEntry],
|
||||
sect: str
|
||||
) -> typing.List:
|
||||
"""Inner helper function to calculate size change for a section.
|
||||
|
||||
Convention for special cases:
|
||||
- If the object has been removed in new Git revision,
|
||||
the size is minus code size of old Git revision;
|
||||
the size change is marked as `Removed`,
|
||||
- If the object only exists in new Git revision,
|
||||
the size is code size of new Git revision;
|
||||
the size change is marked as `None`,
|
||||
|
||||
:param: old_size: code size for objects in old Git revision.
|
||||
:param: new_size: code size for objects in new Git revision.
|
||||
:param: sect: section to calculate from `size` tool. This could be
|
||||
any instance variable in SizeEntry.
|
||||
:return: List of [section size of objects for new Git revision,
|
||||
section size of objects for old Git revision,
|
||||
section size change of objects between two Git revisions]
|
||||
"""
|
||||
if old_size and new_size:
|
||||
new_attr = new_size.__dict__[sect]
|
||||
old_attr = old_size.__dict__[sect]
|
||||
delta = new_attr - old_attr
|
||||
change_attr = '{0:{1}}'.format(delta, '+' if delta else '')
|
||||
elif old_size:
|
||||
new_attr = 'Removed'
|
||||
old_attr = old_size.__dict__[sect]
|
||||
delta = - old_attr
|
||||
change_attr = '{0:{1}}'.format(delta, '+' if delta else '')
|
||||
elif new_size:
|
||||
new_attr = new_size.__dict__[sect]
|
||||
old_attr = 'NotCreated'
|
||||
delta = new_attr
|
||||
change_attr = '{0:{1}}'.format(delta, '+' if delta else '')
|
||||
else:
|
||||
# Should never happen
|
||||
new_attr = 'Error'
|
||||
old_attr = 'Error'
|
||||
change_attr = 'Error'
|
||||
return [new_attr, old_attr, change_attr]
|
||||
|
||||
# sort dictionary by key
|
||||
sort_by_k = lambda item: item[0].lower()
|
||||
def get_results(
|
||||
f_rev_size:
|
||||
typing.Dict[str,
|
||||
typing.Dict[str,
|
||||
CodeSizeGeneratorWithSize.SizeEntry]]
|
||||
) -> typing.List:
|
||||
"""Return List of results in the format of:
|
||||
[filename, new(text), old(text), change(text),
|
||||
new(data), old(data), change(data)]
|
||||
"""
|
||||
res = []
|
||||
for fname, revs_size in sorted(f_rev_size.items(), key=sort_by_k):
|
||||
old_size = revs_size.get(old_rev)
|
||||
new_size = revs_size.get(new_rev)
|
||||
|
||||
text_sect = cal_sect_change(old_size, new_size, 'text')
|
||||
data_sect = cal_sect_change(old_size, new_size, 'data')
|
||||
# skip the files that haven't changed in code size
|
||||
if not show_all and text_sect[-1] == '0' and data_sect[-1] == '0':
|
||||
continue
|
||||
|
||||
res.append([fname, *text_sect, *data_sect])
|
||||
return res
|
||||
|
||||
# write header
|
||||
output.write(line_format.format(*header_line))
|
||||
if with_markdown:
|
||||
output.write(line_format.format(*dash_line))
|
||||
for mod in MBEDTLS_STATIC_LIB:
|
||||
# convert self.code_size to:
|
||||
# {
|
||||
# file_name: {
|
||||
# old_rev: SizeEntry,
|
||||
# new_rev: SizeEntry
|
||||
# },
|
||||
# ...
|
||||
# }
|
||||
f_rev_size = {} #type: typing.Dict[str, typing.Dict]
|
||||
for fname, size_entry in self.code_size[old_rev][mod].items():
|
||||
f_rev_size.setdefault(fname, {}).update({old_rev: size_entry})
|
||||
for fname, size_entry in self.code_size[new_rev][mod].items():
|
||||
f_rev_size.setdefault(fname, {}).update({new_rev: size_entry})
|
||||
|
||||
mod_total_sz = f_rev_size.pop(mod + self.mod_total_suffix)
|
||||
res = get_results(f_rev_size)
|
||||
total_clm = get_results({mod + self.mod_total_suffix: mod_total_sz})
|
||||
if with_markdown:
|
||||
# bold row of mod-TOTALS in markdown table
|
||||
total_clm = [[bold_text(j) for j in i] for i in total_clm]
|
||||
res += total_clm
|
||||
|
||||
# write comparison result
|
||||
for line in res:
|
||||
output.write(line_format.format(*line))
|
||||
|
||||
|
||||
class CodeSizeComparison:
|
||||
"""Compare code size between two Git revisions."""
|
||||
|
||||
def __init__( #pylint: disable=too-many-arguments
|
||||
self,
|
||||
old_size_dist_info: CodeSizeDistinctInfo,
|
||||
new_size_dist_info: CodeSizeDistinctInfo,
|
||||
size_common_info: CodeSizeCommonInfo,
|
||||
result_options: CodeSizeResultInfo,
|
||||
logger: logging.Logger,
|
||||
) -> None:
|
||||
"""
|
||||
:param old_size_dist_info: CodeSizeDistinctInfo containing old distinct
|
||||
info to compare code size with.
|
||||
:param new_size_dist_info: CodeSizeDistinctInfo containing new distinct
|
||||
info to take as comparision base.
|
||||
:param size_common_info: CodeSizeCommonInfo containing common info for
|
||||
both old and new size distinct info and
|
||||
measurement tool.
|
||||
:param result_options: CodeSizeResultInfo containing results options for
|
||||
code size record and comparision.
|
||||
:param logger: logging module
|
||||
"""
|
||||
|
||||
self.logger = logger
|
||||
|
||||
self.old_size_dist_info = old_size_dist_info
|
||||
self.new_size_dist_info = new_size_dist_info
|
||||
self.size_common_info = size_common_info
|
||||
# infer pre make command
|
||||
self.old_size_dist_info.pre_make_cmd = CodeSizeBuildInfo(
|
||||
self.old_size_dist_info, self.size_common_info.host_arch,
|
||||
self.logger).infer_pre_make_command()
|
||||
self.new_size_dist_info.pre_make_cmd = CodeSizeBuildInfo(
|
||||
self.new_size_dist_info, self.size_common_info.host_arch,
|
||||
self.logger).infer_pre_make_command()
|
||||
# infer make command
|
||||
self.old_size_dist_info.make_cmd = CodeSizeBuildInfo(
|
||||
self.old_size_dist_info, self.size_common_info.host_arch,
|
||||
self.logger).infer_make_command()
|
||||
self.new_size_dist_info.make_cmd = CodeSizeBuildInfo(
|
||||
self.new_size_dist_info, self.size_common_info.host_arch,
|
||||
self.logger).infer_make_command()
|
||||
# initialize size parser with corresponding measurement tool
|
||||
self.code_size_generator = self.__generate_size_parser()
|
||||
|
||||
self.result_options = result_options
|
||||
self.csv_dir = os.path.abspath(self.result_options.record_dir)
|
||||
os.makedirs(self.csv_dir, exist_ok=True)
|
||||
self.comp_dir = os.path.abspath(self.result_options.comp_dir)
|
||||
os.makedirs(self.comp_dir, exist_ok=True)
|
||||
|
||||
def __generate_size_parser(self):
|
||||
"""Generate a parser for the corresponding measurement tool."""
|
||||
if re.match(r'size', self.size_common_info.measure_cmd.strip()):
|
||||
return CodeSizeGeneratorWithSize(self.logger)
|
||||
else:
|
||||
self.logger.error("Unsupported measurement tool: `{}`."
|
||||
.format(self.size_common_info.measure_cmd
|
||||
.strip().split(' ')[0]))
|
||||
sys.exit(1)
|
||||
|
||||
def cal_code_size(
|
||||
self,
|
||||
size_dist_info: CodeSizeDistinctInfo
|
||||
) -> typing.Dict[str, str]:
|
||||
"""Calculate code size of library/*.o in a UTF-8 encoding"""
|
||||
|
||||
return CodeSizeCalculator(size_dist_info.git_rev,
|
||||
size_dist_info.pre_make_cmd,
|
||||
size_dist_info.make_cmd,
|
||||
self.size_common_info.measure_cmd,
|
||||
self.logger).cal_libraries_code_size()
|
||||
|
||||
def gen_code_size_report(self, size_dist_info: CodeSizeDistinctInfo) -> None:
|
||||
"""Generate code size record and write it into a file."""
|
||||
|
||||
self.logger.info("Start to generate code size record for {}."
|
||||
.format(size_dist_info.git_rev))
|
||||
output_file = os.path.join(
|
||||
self.csv_dir,
|
||||
'{}-{}.csv'
|
||||
.format(size_dist_info.get_info_indication(),
|
||||
self.size_common_info.get_info_indication()))
|
||||
# Check if the corresponding record exists
|
||||
if size_dist_info.git_rev != "current" and \
|
||||
os.path.exists(output_file):
|
||||
self.logger.debug("Code size csv file for {} already exists."
|
||||
.format(size_dist_info.git_rev))
|
||||
self.code_size_generator.read_size_record(
|
||||
size_dist_info.git_rev, output_file)
|
||||
else:
|
||||
# measure code size
|
||||
code_size_text = self.cal_code_size(size_dist_info)
|
||||
|
||||
self.logger.debug("Generating code size csv for {}."
|
||||
.format(size_dist_info.git_rev))
|
||||
output = open(output_file, "w")
|
||||
self.code_size_generator.write_record(
|
||||
size_dist_info.git_rev, code_size_text, output)
|
||||
|
||||
def gen_code_size_comparison(self) -> None:
|
||||
"""Generate results of code size changes between two Git revisions,
|
||||
old and new.
|
||||
|
||||
- Measured code size result of these two Git revisions must be available.
|
||||
- The result is directed into either file / stdout depending on
|
||||
the option, size_common_info.result_options.stdout. (Default: file)
|
||||
"""
|
||||
|
||||
self.logger.info("Start to generate comparision result between "\
|
||||
"{} and {}."
|
||||
.format(self.old_size_dist_info.git_rev,
|
||||
self.new_size_dist_info.git_rev))
|
||||
if self.result_options.stdout:
|
||||
output = sys.stdout
|
||||
else:
|
||||
output_file = os.path.join(
|
||||
self.comp_dir,
|
||||
'{}-{}-{}.{}'
|
||||
.format(self.old_size_dist_info.get_info_indication(),
|
||||
self.new_size_dist_info.get_info_indication(),
|
||||
self.size_common_info.get_info_indication(),
|
||||
'md' if self.result_options.with_markdown else 'csv'))
|
||||
output = open(output_file, "w")
|
||||
|
||||
self.logger.debug("Generating comparison results between {} and {}."
|
||||
.format(self.old_size_dist_info.git_rev,
|
||||
self.new_size_dist_info.git_rev))
|
||||
if self.result_options.with_markdown or self.result_options.stdout:
|
||||
print("Measure code size between {} and {} by `{}`."
|
||||
.format(self.old_size_dist_info.get_info_indication(),
|
||||
self.new_size_dist_info.get_info_indication(),
|
||||
self.size_common_info.get_info_indication()),
|
||||
file=output)
|
||||
self.code_size_generator.write_comparison(
|
||||
self.old_size_dist_info.git_rev,
|
||||
self.new_size_dist_info.git_rev,
|
||||
output, self.result_options.with_markdown,
|
||||
self.result_options.show_all)
|
||||
|
||||
def get_comparision_results(self) -> None:
|
||||
"""Compare size of library/*.o between self.old_size_dist_info and
|
||||
self.old_size_dist_info and generate the result file."""
|
||||
build_tree.check_repo_path()
|
||||
self.gen_code_size_report(self.old_size_dist_info)
|
||||
self.gen_code_size_report(self.new_size_dist_info)
|
||||
self.gen_code_size_comparison()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=(__doc__))
|
||||
group_required = parser.add_argument_group(
|
||||
'required arguments',
|
||||
'required arguments to parse for running ' + os.path.basename(__file__))
|
||||
group_required.add_argument(
|
||||
'-o', '--old-rev', type=str, required=True,
|
||||
help='old Git revision for comparison.')
|
||||
|
||||
group_optional = parser.add_argument_group(
|
||||
'optional arguments',
|
||||
'optional arguments to parse for running ' + os.path.basename(__file__))
|
||||
group_optional.add_argument(
|
||||
'--record-dir', type=str, default='code_size_records',
|
||||
help='directory where code size record is stored. '
|
||||
'(Default: code_size_records)')
|
||||
group_optional.add_argument(
|
||||
'--comp-dir', type=str, default='comparison',
|
||||
help='directory where comparison result is stored. '
|
||||
'(Default: comparison)')
|
||||
group_optional.add_argument(
|
||||
'-n', '--new-rev', type=str, default='current',
|
||||
help='new Git revision as comparison base. '
|
||||
'(Default is the current work directory, including uncommitted '
|
||||
'changes.)')
|
||||
group_optional.add_argument(
|
||||
'-a', '--arch', type=str, default=detect_arch(),
|
||||
choices=list(map(lambda s: s.value, SupportedArch)),
|
||||
help='Specify architecture for code size comparison. '
|
||||
'(Default is the host architecture.)')
|
||||
group_optional.add_argument(
|
||||
'-c', '--config', type=str, default=SupportedConfig.DEFAULT.value,
|
||||
choices=list(map(lambda s: s.value, SupportedConfig)),
|
||||
help='Specify configuration type for code size comparison. '
|
||||
'(Default is the current Mbed TLS configuration.)')
|
||||
group_optional.add_argument(
|
||||
'--markdown', action='store_true', dest='markdown',
|
||||
help='Show comparision of code size in a markdown table. '
|
||||
'(Only show the files that have changed).')
|
||||
group_optional.add_argument(
|
||||
'--stdout', action='store_true', dest='stdout',
|
||||
help='Set this option to direct comparison result into sys.stdout. '
|
||||
'(Default: file)')
|
||||
group_optional.add_argument(
|
||||
'--show-all', action='store_true', dest='show_all',
|
||||
help='Show all the objects in comparison result, including the ones '
|
||||
'that haven\'t changed in code size. (Default: False)')
|
||||
group_optional.add_argument(
|
||||
'--verbose', action='store_true', dest='verbose',
|
||||
help='Show logs in detail for code size measurement. '
|
||||
'(Default: False)')
|
||||
comp_args = parser.parse_args()
|
||||
|
||||
logger = logging.getLogger()
|
||||
logging_util.configure_logger(logger, split_level=logging.NOTSET)
|
||||
logger.setLevel(logging.DEBUG if comp_args.verbose else logging.INFO)
|
||||
|
||||
if os.path.isfile(comp_args.record_dir):
|
||||
logger.error("record directory: {} is not a directory"
|
||||
.format(comp_args.record_dir))
|
||||
sys.exit(1)
|
||||
if os.path.isfile(comp_args.comp_dir):
|
||||
logger.error("comparison directory: {} is not a directory"
|
||||
.format(comp_args.comp_dir))
|
||||
sys.exit(1)
|
||||
|
||||
comp_args.old_rev = CodeSizeCalculator.validate_git_revision(
|
||||
comp_args.old_rev)
|
||||
if comp_args.new_rev != 'current':
|
||||
comp_args.new_rev = CodeSizeCalculator.validate_git_revision(
|
||||
comp_args.new_rev)
|
||||
|
||||
# version, git_rev, arch, config, compiler, opt_level
|
||||
old_size_dist_info = CodeSizeDistinctInfo(
|
||||
'old', comp_args.old_rev, comp_args.arch, comp_args.config, 'cc', '-Os')
|
||||
new_size_dist_info = CodeSizeDistinctInfo(
|
||||
'new', comp_args.new_rev, comp_args.arch, comp_args.config, 'cc', '-Os')
|
||||
# host_arch, measure_cmd
|
||||
size_common_info = CodeSizeCommonInfo(
|
||||
detect_arch(), 'size -t')
|
||||
# record_dir, comp_dir, with_markdown, stdout, show_all
|
||||
result_options = CodeSizeResultInfo(
|
||||
comp_args.record_dir, comp_args.comp_dir,
|
||||
comp_args.markdown, comp_args.stdout, comp_args.show_all)
|
||||
|
||||
logger.info("Measure code size between {} and {} by `{}`."
|
||||
.format(old_size_dist_info.get_info_indication(),
|
||||
new_size_dist_info.get_info_indication(),
|
||||
size_common_info.get_info_indication()))
|
||||
CodeSizeComparison(old_size_dist_info, new_size_dist_info,
|
||||
size_common_info, result_options,
|
||||
logger).get_comparision_results()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,271 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Check or fix the code style by running Uncrustify.
|
||||
|
||||
This script must be run from the root of a Git work tree containing Mbed TLS.
|
||||
"""
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import FrozenSet, List, Optional
|
||||
|
||||
UNCRUSTIFY_SUPPORTED_VERSION = "0.75.1"
|
||||
CONFIG_FILE = ".uncrustify.cfg"
|
||||
UNCRUSTIFY_EXE = "uncrustify"
|
||||
UNCRUSTIFY_ARGS = ["-c", CONFIG_FILE]
|
||||
CHECK_GENERATED_FILES = "tests/scripts/check-generated-files.sh"
|
||||
|
||||
def print_err(*args):
|
||||
print("Error: ", *args, file=sys.stderr)
|
||||
|
||||
# Print the file names that will be skipped and the help message
|
||||
def print_skip(files_to_skip):
|
||||
print()
|
||||
print(*files_to_skip, sep=", SKIP\n", end=", SKIP\n")
|
||||
print("Warning: The listed files will be skipped because\n"
|
||||
"they are not known to git.")
|
||||
print()
|
||||
|
||||
# Match FILENAME(s) in "check SCRIPT (FILENAME...)"
|
||||
CHECK_CALL_RE = re.compile(r"\n\s*check\s+[^\s#$&*?;|]+([^\n#$&*?;|]+)",
|
||||
re.ASCII)
|
||||
def list_generated_files() -> FrozenSet[str]:
|
||||
"""Return the names of generated files.
|
||||
|
||||
We don't reformat generated files, since the result might be different
|
||||
from the output of the generator. Ideally the result of the generator
|
||||
would conform to the code style, but this would be difficult, especially
|
||||
with respect to the placement of line breaks in long logical lines.
|
||||
"""
|
||||
# Parse check-generated-files.sh to get an up-to-date list of
|
||||
# generated files. Read the file rather than calling it so that
|
||||
# this script only depends on Git, Python and uncrustify, and not other
|
||||
# tools such as sh or grep which might not be available on Windows.
|
||||
# This introduces a limitation: check-generated-files.sh must have
|
||||
# the expected format and must list the files explicitly, not through
|
||||
# wildcards or command substitution.
|
||||
content = open(CHECK_GENERATED_FILES, encoding="utf-8").read()
|
||||
checks = re.findall(CHECK_CALL_RE, content)
|
||||
return frozenset(word for s in checks for word in s.split())
|
||||
|
||||
# Check for comment string indicating an auto-generated file
|
||||
AUTOGEN_RE = re.compile(r"Warning[ :-]+This file is (now )?auto[ -]?generated",
|
||||
re.ASCII | re.IGNORECASE)
|
||||
def is_file_autogenerated(filename):
|
||||
content = open(filename, encoding="utf-8").read()
|
||||
return AUTOGEN_RE.search(content) is not None
|
||||
|
||||
def get_src_files(since: Optional[str]) -> List[str]:
|
||||
"""
|
||||
Use git to get a list of the source files.
|
||||
|
||||
The optional argument since is a commit, indicating to only list files
|
||||
that have changed since that commit. Without this argument, list all
|
||||
files known to git.
|
||||
|
||||
Only C files are included, and certain files (generated, or third party)
|
||||
are excluded.
|
||||
"""
|
||||
file_patterns = ["*.[hc]",
|
||||
"tests/suites/*.function",
|
||||
"tf-psa-crypto/tests/suites/*.function",
|
||||
"scripts/data_files/*.fmt"]
|
||||
output = subprocess.check_output(["git", "ls-files"] + file_patterns,
|
||||
universal_newlines=True)
|
||||
src_files = output.split()
|
||||
|
||||
# When this script is called from a git hook, some environment variables
|
||||
# are set by default which force all git commands to use the main repository
|
||||
# (i.e. prevent us from performing commands on the framework repo).
|
||||
# Create an environment without these variables for running commands on the
|
||||
# framework repo.
|
||||
framework_env = os.environ.copy()
|
||||
# Get a list of environment vars that git sets
|
||||
git_env_vars = subprocess.check_output(["git", "rev-parse", "--local-env-vars"],
|
||||
universal_newlines=True)
|
||||
# Remove the vars from the environment
|
||||
for var in git_env_vars.split():
|
||||
framework_env.pop(var, None)
|
||||
|
||||
output = subprocess.check_output(["git", "-C", "framework", "ls-files"]
|
||||
+ file_patterns,
|
||||
universal_newlines=True,
|
||||
env=framework_env)
|
||||
framework_src_files = output.split()
|
||||
|
||||
if since:
|
||||
# get all files changed in commits since the starting point in ...
|
||||
# ... the main repository
|
||||
cmd = ["git", "log", since + "..HEAD", "--ignore-submodules",
|
||||
"--name-only", "--pretty=", "--"] + src_files
|
||||
output = subprocess.check_output(cmd, universal_newlines=True)
|
||||
committed_changed_files = output.split()
|
||||
# ... the framework submodule
|
||||
cmd = ["git", "-C", "framework", "log", since + "..HEAD",
|
||||
"--name-only", "--pretty=", "--"] + framework_src_files
|
||||
output = subprocess.check_output(cmd, universal_newlines=True,
|
||||
env=framework_env)
|
||||
committed_changed_files += ["framework/" + s for s in output.split()]
|
||||
|
||||
# and also get all files with uncommitted changes in ...
|
||||
# ... the main repository
|
||||
cmd = ["git", "diff", "--name-only", "--"] + src_files
|
||||
output = subprocess.check_output(cmd, universal_newlines=True)
|
||||
uncommitted_changed_files = output.split()
|
||||
# ... the framework submodule
|
||||
cmd = ["git", "-C", "framework", "diff", "--name-only", "--"] + \
|
||||
framework_src_files
|
||||
output = subprocess.check_output(cmd, universal_newlines=True,
|
||||
env=framework_env)
|
||||
uncommitted_changed_files += ["framework/" + s for s in output.split()]
|
||||
|
||||
src_files = committed_changed_files + uncommitted_changed_files
|
||||
else:
|
||||
src_files += ["framework/" + s for s in framework_src_files]
|
||||
|
||||
generated_files = list_generated_files()
|
||||
# Don't correct style for third-party files (and, for simplicity,
|
||||
# companion files in the same subtree), or for automatically
|
||||
# generated files (we're correcting the templates instead).
|
||||
src_files = [filename for filename in src_files
|
||||
if not (filename.startswith("tf-psa-crypto/drivers/everest/") or
|
||||
filename.startswith("tf-psa-crypto/drivers/p256-m/") or
|
||||
filename in generated_files or
|
||||
is_file_autogenerated(filename))]
|
||||
return src_files
|
||||
|
||||
def get_uncrustify_version() -> str:
|
||||
"""
|
||||
Get the version string from Uncrustify
|
||||
"""
|
||||
result = subprocess.run([UNCRUSTIFY_EXE, "--version"],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
check=False)
|
||||
if result.returncode != 0:
|
||||
print_err("Could not get Uncrustify version:", str(result.stderr, "utf-8"))
|
||||
return ""
|
||||
else:
|
||||
return str(result.stdout, "utf-8")
|
||||
|
||||
def check_style_is_correct(src_file_list: List[str]) -> bool:
|
||||
"""
|
||||
Check the code style and output a diff for each file whose style is
|
||||
incorrect.
|
||||
"""
|
||||
style_correct = True
|
||||
for src_file in src_file_list:
|
||||
uncrustify_cmd = [UNCRUSTIFY_EXE] + UNCRUSTIFY_ARGS + [src_file]
|
||||
result = subprocess.run(uncrustify_cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, check=False)
|
||||
if result.returncode != 0:
|
||||
print_err("Uncrustify returned " + str(result.returncode) +
|
||||
" correcting file " + src_file)
|
||||
return False
|
||||
|
||||
# Uncrustify makes changes to the code and places the result in a new
|
||||
# file with the extension ".uncrustify". To get the changes (if any)
|
||||
# simply diff the 2 files.
|
||||
diff_cmd = ["diff", "-u", src_file, src_file + ".uncrustify"]
|
||||
cp = subprocess.run(diff_cmd, check=False)
|
||||
|
||||
if cp.returncode == 1:
|
||||
print(src_file + " changed - code style is incorrect.")
|
||||
style_correct = False
|
||||
elif cp.returncode != 0:
|
||||
raise subprocess.CalledProcessError(cp.returncode, cp.args,
|
||||
cp.stdout, cp.stderr)
|
||||
|
||||
# Tidy up artifact
|
||||
os.remove(src_file + ".uncrustify")
|
||||
|
||||
return style_correct
|
||||
|
||||
def fix_style_single_pass(src_file_list: List[str]) -> bool:
|
||||
"""
|
||||
Run Uncrustify once over the source files.
|
||||
"""
|
||||
code_change_args = UNCRUSTIFY_ARGS + ["--no-backup"]
|
||||
for src_file in src_file_list:
|
||||
uncrustify_cmd = [UNCRUSTIFY_EXE] + code_change_args + [src_file]
|
||||
result = subprocess.run(uncrustify_cmd, check=False)
|
||||
if result.returncode != 0:
|
||||
print_err("Uncrustify with file returned: " +
|
||||
str(result.returncode) + " correcting file " +
|
||||
src_file)
|
||||
return False
|
||||
return True
|
||||
|
||||
def fix_style(src_file_list: List[str]) -> int:
|
||||
"""
|
||||
Fix the code style. This takes 2 passes of Uncrustify.
|
||||
"""
|
||||
if not fix_style_single_pass(src_file_list):
|
||||
return 1
|
||||
if not fix_style_single_pass(src_file_list):
|
||||
return 1
|
||||
|
||||
# Guard against future changes that cause the codebase to require
|
||||
# more passes.
|
||||
if not check_style_is_correct(src_file_list):
|
||||
print_err("Code style still incorrect after second run of Uncrustify.")
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def main() -> int:
|
||||
"""
|
||||
Main with command line arguments.
|
||||
"""
|
||||
uncrustify_version = get_uncrustify_version().strip()
|
||||
if UNCRUSTIFY_SUPPORTED_VERSION not in uncrustify_version:
|
||||
print("Warning: Using unsupported Uncrustify version '" +
|
||||
uncrustify_version + "'")
|
||||
print("Note: The only supported version is " +
|
||||
UNCRUSTIFY_SUPPORTED_VERSION)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-f', '--fix', action='store_true',
|
||||
help=('modify source files to fix the code style '
|
||||
'(default: print diff, do not modify files)'))
|
||||
parser.add_argument('-s', '--since', metavar='COMMIT', const='development', nargs='?',
|
||||
help=('only check files modified since the specified commit'
|
||||
' (e.g. --since=HEAD~3 or --since=development). If no'
|
||||
' commit is specified, default to development.'))
|
||||
# --subset is almost useless: it only matters if there are no files
|
||||
# ('code_style.py' without arguments checks all files known to Git,
|
||||
# 'code_style.py --subset' does nothing). In particular,
|
||||
# 'code_style.py --fix --subset ...' is intended as a stable ("porcelain")
|
||||
# way to restyle a possibly empty set of files.
|
||||
parser.add_argument('--subset', action='store_true',
|
||||
help='only check the specified files (default with non-option arguments)')
|
||||
parser.add_argument('operands', nargs='*', metavar='FILE',
|
||||
help='files to check (files MUST be known to git, if none: check all)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
covered = frozenset(get_src_files(args.since))
|
||||
# We only check files that are known to git
|
||||
if args.subset or args.operands:
|
||||
src_files = [f for f in args.operands if f in covered]
|
||||
skip_src_files = [f for f in args.operands if f not in covered]
|
||||
if skip_src_files:
|
||||
print_skip(skip_src_files)
|
||||
else:
|
||||
src_files = list(covered)
|
||||
|
||||
if args.fix:
|
||||
# Fix mode
|
||||
return fix_style(src_files)
|
||||
else:
|
||||
# Check mode
|
||||
if check_style_is_correct(src_files):
|
||||
print("Checked {} files, style ok.".format(len(src_files)))
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,168 +0,0 @@
|
||||
# To compile on SunOS: add "-lsocket -lnsl" to LDFLAGS
|
||||
|
||||
ifndef MBEDTLS_PATH
|
||||
MBEDTLS_PATH := ..
|
||||
endif
|
||||
|
||||
PSASIM_PATH=$(MBEDTLS_PATH)/tests/psa-client-server/psasim
|
||||
|
||||
ifeq (,$(wildcard $(MBEDTLS_PATH)/framework/exported.make))
|
||||
# Use the define keyword to get a multi-line message.
|
||||
# GNU make appends ". Stop.", so tweak the ending of our message accordingly.
|
||||
define error_message
|
||||
$(MBEDTLS_PATH)/framework/exported.make not found.
|
||||
Run `git submodule update --init` to fetch the submodule contents.
|
||||
This is a fatal error
|
||||
endef
|
||||
$(error $(error_message))
|
||||
endif
|
||||
include $(MBEDTLS_PATH)/framework/exported.make
|
||||
|
||||
CFLAGS ?= -O2
|
||||
WARNING_CFLAGS ?= -Wall -Wextra -Wformat=2 -Wno-format-nonliteral
|
||||
WARNING_CXXFLAGS ?= -Wall -Wextra -Wformat=2 -Wno-format-nonliteral -std=c++11 -pedantic
|
||||
LDFLAGS ?=
|
||||
|
||||
LOCAL_CFLAGS = $(WARNING_CFLAGS) -I$(MBEDTLS_TEST_PATH)/include \
|
||||
-I$(MBEDTLS_PATH)/include -I$(MBEDTLS_PATH)/tf-psa-crypto/include \
|
||||
-I$(MBEDTLS_PATH)/tf-psa-crypto/drivers/builtin/include \
|
||||
-D_FILE_OFFSET_BITS=64
|
||||
LOCAL_CXXFLAGS = $(WARNING_CXXFLAGS) $(LOCAL_CFLAGS)
|
||||
|
||||
ifdef PSASIM
|
||||
LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS} \
|
||||
-L$(PSASIM_PATH)/client_libs \
|
||||
-lpsaclient \
|
||||
-lmbedtls$(SHARED_SUFFIX) \
|
||||
-lmbedx509$(SHARED_SUFFIX) \
|
||||
-lmbedcrypto$(SHARED_SUFFIX)
|
||||
else
|
||||
LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS} \
|
||||
-L$(MBEDTLS_PATH)/library \
|
||||
-lmbedtls$(SHARED_SUFFIX) \
|
||||
-lmbedx509$(SHARED_SUFFIX) \
|
||||
-lmbedcrypto$(SHARED_SUFFIX)
|
||||
endif
|
||||
|
||||
THIRDPARTY_DIR = $(MBEDTLS_PATH)/tf-psa-crypto/drivers
|
||||
include $(THIRDPARTY_DIR)/everest/Makefile.inc
|
||||
include $(THIRDPARTY_DIR)/p256-m/Makefile.inc
|
||||
LOCAL_CFLAGS+=$(THIRDPARTY_INCLUDES)
|
||||
|
||||
ifdef PSASIM
|
||||
MBEDLIBS=$(PSASIM_PATH)/client_libs/libmbedcrypto.a \
|
||||
$(PSASIM_PATH)/client_libs/libmbedx509.a \
|
||||
$(PSASIM_PATH)/client_libs/libmbedtls.a \
|
||||
$(PSASIM_PATH)/client_libs/libpsaclient.a
|
||||
else ifndef SHARED
|
||||
MBEDLIBS=$(MBEDTLS_PATH)/library/libmbedcrypto.a \
|
||||
$(MBEDTLS_PATH)/library/libmbedx509.a \
|
||||
$(MBEDTLS_PATH)/library/libmbedtls.a
|
||||
else
|
||||
MBEDLIBS=$(MBEDTLS_PATH)/library/libmbedcrypto.$(DLEXT) \
|
||||
$(MBEDTLS_PATH)/library/libmbedx509.$(DLEXT) \
|
||||
$(MBEDTLS_PATH)/library/libmbedtls.$(DLEXT)
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
LOCAL_CFLAGS += -g3
|
||||
endif
|
||||
|
||||
# if we're running on Windows, build for Windows
|
||||
ifdef WINDOWS
|
||||
WINDOWS_BUILD=1
|
||||
endif
|
||||
|
||||
## Usage: $(call remove_enabled_options,PREPROCESSOR_INPUT)
|
||||
## Remove the preprocessor symbols that are set in the current configuration
|
||||
## from PREPROCESSOR_INPUT. Also normalize whitespace.
|
||||
## Example:
|
||||
## $(call remove_enabled_options,MBEDTLS_FOO MBEDTLS_BAR)
|
||||
## This expands to an empty string "" if MBEDTLS_FOO and MBEDTLS_BAR are both
|
||||
## enabled, to "MBEDTLS_FOO" if MBEDTLS_BAR is enabled but MBEDTLS_FOO is
|
||||
## disabled, etc.
|
||||
##
|
||||
## This only works with a Unix-like shell environment (Bourne/POSIX-style shell
|
||||
## and standard commands) and a Unix-like compiler (supporting -E). In
|
||||
## other environments, the output is likely to be empty.
|
||||
define remove_enabled_options
|
||||
$(strip $(shell
|
||||
exec 2>/dev/null;
|
||||
{ echo '#include <mbedtls/build_info.h>'; echo $(1); } |
|
||||
$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -E - |
|
||||
tail -n 1
|
||||
))
|
||||
endef
|
||||
|
||||
ifdef WINDOWS_BUILD
|
||||
DLEXT=dll
|
||||
EXEXT=.exe
|
||||
LOCAL_LDFLAGS += -lws2_32 -lbcrypt
|
||||
ifdef SHARED
|
||||
SHARED_SUFFIX=.$(DLEXT)
|
||||
endif
|
||||
|
||||
else # Not building for Windows
|
||||
DLEXT ?= so
|
||||
EXEXT=
|
||||
SHARED_SUFFIX=
|
||||
ifndef THREADING
|
||||
# Auto-detect configurations with pthread.
|
||||
# If the call to remove_enabled_options returns "control", the symbols
|
||||
# are confirmed set and we link with pthread.
|
||||
# If the auto-detection fails, the result of the call is empty and
|
||||
# we keep THREADING undefined.
|
||||
ifeq (control,$(call remove_enabled_options,control MBEDTLS_THREADING_C MBEDTLS_THREADING_PTHREAD))
|
||||
THREADING := pthread
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(THREADING),pthread)
|
||||
LOCAL_LDFLAGS += -lpthread
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef WINDOWS
|
||||
PYTHON ?= python
|
||||
else
|
||||
PYTHON ?= $(shell if type python3 >/dev/null 2>/dev/null; then echo python3; else echo python; fi)
|
||||
endif
|
||||
|
||||
# See root Makefile
|
||||
GEN_FILES ?= yes
|
||||
ifdef GEN_FILES
|
||||
gen_file_dep =
|
||||
else
|
||||
gen_file_dep = |
|
||||
endif
|
||||
|
||||
default: all
|
||||
|
||||
$(MBEDLIBS):
|
||||
$(MAKE) -C $(MBEDTLS_PATH)/library
|
||||
|
||||
neat: clean
|
||||
ifndef WINDOWS
|
||||
rm -f $(GENERATED_FILES)
|
||||
else
|
||||
for %f in ($(subst /,\,$(GENERATED_FILES))) if exist %f del /Q /F %f
|
||||
endif
|
||||
|
||||
# Auxiliary modules used by tests and some sample programs
|
||||
MBEDTLS_CORE_TEST_OBJS := $(patsubst %.c,%.o,$(wildcard \
|
||||
${MBEDTLS_TEST_PATH}/src/*.c \
|
||||
${MBEDTLS_TEST_PATH}/src/drivers/*.c \
|
||||
))
|
||||
# Ignore PSA stubs when building for the client side of PSASIM (i.e.
|
||||
# CRYPTO_CLIENT && !CRYPTO_C) otherwise there will be functions duplicates.
|
||||
ifdef PSASIM
|
||||
MBEDTLS_CORE_TEST_OBJS := $(filter-out \
|
||||
${MBEDTLS_TEST_PATH}/src/psa_crypto_stubs.o, $(MBEDTLS_CORE_TEST_OBJS)\
|
||||
)
|
||||
endif
|
||||
# Additional auxiliary modules for TLS testing
|
||||
MBEDTLS_TLS_TEST_OBJS = $(patsubst %.c,%.o,$(wildcard \
|
||||
${MBEDTLS_TEST_PATH}/src/test_helpers/*.c \
|
||||
))
|
||||
|
||||
MBEDTLS_TEST_OBJS = $(MBEDTLS_CORE_TEST_OBJS) $(MBEDTLS_TLS_TEST_OBJS)
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
# Backward compatibility redirection
|
||||
|
||||
## Copyright The Mbed TLS Contributors
|
||||
## SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
##
|
||||
|
||||
my $py = $0;
|
||||
$py =~ s/\.pl$/.py/ or die "Unable to determine the name of the Python script";
|
||||
exec 'python3', $py, @ARGV;
|
||||
print STDERR "$0: python3: $!. Trying python instead.\n";
|
||||
exec 'python', $py, @ARGV;
|
||||
print STDERR "$0: python: $!\n";
|
||||
exit 127;
|
||||
@@ -1,509 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Mbed TLS and PSA configuration file manipulation library and tool
|
||||
|
||||
Basic usage, to read the Mbed TLS configuration:
|
||||
config = CombinedConfigFile()
|
||||
if 'MBEDTLS_RSA_C' in config: print('RSA is enabled')
|
||||
"""
|
||||
|
||||
## Copyright The Mbed TLS Contributors
|
||||
## SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
##
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import config_common
|
||||
|
||||
|
||||
def is_boolean_setting(name, value):
|
||||
"""Is this a boolean setting?
|
||||
|
||||
Mbed TLS boolean settings are enabled if the preprocessor macro is
|
||||
defined, and disabled if the preprocessor macro is not defined. The
|
||||
macro definition line in the configuration file has an empty expansion.
|
||||
|
||||
PSA_WANT_xxx settings are also boolean, but when they are enabled,
|
||||
they expand to a nonzero value. We leave them undefined when they
|
||||
are disabled. (Setting them to 0 currently means to enable them, but
|
||||
this might change to mean disabling them. Currently we just never set
|
||||
them to 0.)
|
||||
"""
|
||||
if name.startswith('PSA_WANT_'):
|
||||
return True
|
||||
if not value:
|
||||
return True
|
||||
return False
|
||||
|
||||
def realfull_adapter(_name, _value, _active):
|
||||
"""Activate all symbols.
|
||||
|
||||
This is intended for building the documentation, including the
|
||||
documentation of settings that are activated by defining an optional
|
||||
preprocessor macro. There is no expectation that the resulting
|
||||
configuration can be built.
|
||||
"""
|
||||
return True
|
||||
|
||||
PSA_UNSUPPORTED_FEATURE = frozenset([
|
||||
'PSA_WANT_ALG_CBC_MAC',
|
||||
'PSA_WANT_ALG_XTS',
|
||||
'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE',
|
||||
'PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE'
|
||||
])
|
||||
|
||||
PSA_DEPRECATED_FEATURE = frozenset([
|
||||
'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR',
|
||||
'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR'
|
||||
])
|
||||
|
||||
PSA_UNSTABLE_FEATURE = frozenset([
|
||||
'PSA_WANT_ECC_SECP_K1_224'
|
||||
])
|
||||
|
||||
EXCLUDE_FROM_CRYPTO = PSA_UNSUPPORTED_FEATURE | \
|
||||
PSA_DEPRECATED_FEATURE | \
|
||||
PSA_UNSTABLE_FEATURE
|
||||
|
||||
# The goal of the full configuration is to have everything that can be tested
|
||||
# together. This includes deprecated or insecure options. It excludes:
|
||||
# * Options that require additional build dependencies or unusual hardware.
|
||||
# * Options that make testing less effective.
|
||||
# * Options that are incompatible with other options, or more generally that
|
||||
# interact with other parts of the code in such a way that a bulk enabling
|
||||
# is not a good way to test them.
|
||||
# * Options that remove features.
|
||||
EXCLUDE_FROM_FULL = frozenset([
|
||||
#pylint: disable=line-too-long
|
||||
'MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH', # interacts with CTR_DRBG_128_BIT_KEY
|
||||
'MBEDTLS_AES_USE_HARDWARE_ONLY', # hardware dependency
|
||||
'MBEDTLS_BLOCK_CIPHER_NO_DECRYPT', # incompatible with ECB in PSA, CBC/XTS/NIST_KW/DES
|
||||
'MBEDTLS_CTR_DRBG_USE_128_BIT_KEY', # interacts with ENTROPY_FORCE_SHA256
|
||||
'MBEDTLS_DEPRECATED_REMOVED', # conflicts with deprecated options
|
||||
'MBEDTLS_DEPRECATED_WARNING', # conflicts with deprecated options
|
||||
'MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED', # influences the use of ECDH in TLS
|
||||
'MBEDTLS_ECP_WITH_MPI_UINT', # disables the default ECP and is experimental
|
||||
'MBEDTLS_ENTROPY_FORCE_SHA256', # interacts with CTR_DRBG_128_BIT_KEY
|
||||
'MBEDTLS_HAVE_SSE2', # hardware dependency
|
||||
'MBEDTLS_MEMORY_BACKTRACE', # depends on MEMORY_BUFFER_ALLOC_C
|
||||
'MBEDTLS_MEMORY_BUFFER_ALLOC_C', # makes sanitizers (e.g. ASan) less effective
|
||||
'MBEDTLS_MEMORY_DEBUG', # depends on MEMORY_BUFFER_ALLOC_C
|
||||
'MBEDTLS_NO_64BIT_MULTIPLICATION', # influences anything that uses bignum
|
||||
'MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES', # removes a feature
|
||||
'MBEDTLS_NO_PLATFORM_ENTROPY', # removes a feature
|
||||
'MBEDTLS_NO_UDBL_DIVISION', # influences anything that uses bignum
|
||||
'MBEDTLS_PSA_P256M_DRIVER_ENABLED', # influences SECP256R1 KeyGen/ECDH/ECDSA
|
||||
'MBEDTLS_PLATFORM_NO_STD_FUNCTIONS', # removes a feature
|
||||
'MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS', # removes a feature
|
||||
'MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG', # behavior change + build dependency
|
||||
'MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER', # interface and behavior change
|
||||
'MBEDTLS_PSA_CRYPTO_SPM', # platform dependency (PSA SPM)
|
||||
'MBEDTLS_PSA_INJECT_ENTROPY', # conflicts with platform entropy sources
|
||||
'MBEDTLS_RSA_NO_CRT', # influences the use of RSA in X.509 and TLS
|
||||
'MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY', # interacts with *_USE_A64_CRYPTO_IF_PRESENT
|
||||
'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY', # interacts with *_USE_ARMV8_A_CRYPTO_IF_PRESENT
|
||||
'MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY', # interacts with *_USE_A64_CRYPTO_IF_PRESENT
|
||||
'MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT', # setting *_USE_ARMV8_A_CRYPTO is sufficient
|
||||
'MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN', # build dependency (clang+memsan)
|
||||
'MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND', # build dependency (valgrind headers)
|
||||
'MBEDTLS_X509_REMOVE_INFO', # removes a feature
|
||||
*PSA_UNSUPPORTED_FEATURE,
|
||||
*PSA_DEPRECATED_FEATURE,
|
||||
*PSA_UNSTABLE_FEATURE
|
||||
])
|
||||
|
||||
def is_seamless_alt(name):
|
||||
"""Whether the xxx_ALT symbol should be included in the full configuration.
|
||||
|
||||
Include alternative implementations of platform functions, which are
|
||||
configurable function pointers that default to the built-in function.
|
||||
This way we test that the function pointers exist and build correctly
|
||||
without changing the behavior, and tests can verify that the function
|
||||
pointers are used by modifying those pointers.
|
||||
|
||||
Exclude alternative implementations of library functions since they require
|
||||
an implementation of the relevant functions and an xxx_alt.h header.
|
||||
"""
|
||||
if name in (
|
||||
'MBEDTLS_PLATFORM_GMTIME_R_ALT',
|
||||
'MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT',
|
||||
'MBEDTLS_PLATFORM_MS_TIME_ALT',
|
||||
'MBEDTLS_PLATFORM_ZEROIZE_ALT',
|
||||
):
|
||||
# Similar to non-platform xxx_ALT, requires platform_alt.h
|
||||
return False
|
||||
return name.startswith('MBEDTLS_PLATFORM_')
|
||||
|
||||
def include_in_full(name):
|
||||
"""Rules for symbols in the "full" configuration."""
|
||||
if name in EXCLUDE_FROM_FULL:
|
||||
return False
|
||||
if name.endswith('_ALT'):
|
||||
return is_seamless_alt(name)
|
||||
return True
|
||||
|
||||
def full_adapter(name, value, active):
|
||||
"""Config adapter for "full"."""
|
||||
if not is_boolean_setting(name, value):
|
||||
return active
|
||||
return include_in_full(name)
|
||||
|
||||
# The baremetal configuration excludes options that require a library or
|
||||
# operating system feature that is typically not present on bare metal
|
||||
# systems. Features that are excluded from "full" won't be in "baremetal"
|
||||
# either (unless explicitly turned on in baremetal_adapter) so they don't
|
||||
# need to be repeated here.
|
||||
EXCLUDE_FROM_BAREMETAL = frozenset([
|
||||
#pylint: disable=line-too-long
|
||||
'MBEDTLS_ENTROPY_NV_SEED', # requires a filesystem and FS_IO or alternate NV seed hooks
|
||||
'MBEDTLS_FS_IO', # requires a filesystem
|
||||
'MBEDTLS_HAVE_TIME', # requires a clock
|
||||
'MBEDTLS_HAVE_TIME_DATE', # requires a clock
|
||||
'MBEDTLS_NET_C', # requires POSIX-like networking
|
||||
'MBEDTLS_PLATFORM_FPRINTF_ALT', # requires FILE* from stdio.h
|
||||
'MBEDTLS_PLATFORM_NV_SEED_ALT', # requires a filesystem and ENTROPY_NV_SEED
|
||||
'MBEDTLS_PLATFORM_TIME_ALT', # requires a clock and HAVE_TIME
|
||||
'MBEDTLS_PSA_CRYPTO_SE_C', # requires a filesystem and PSA_CRYPTO_STORAGE_C
|
||||
'MBEDTLS_PSA_CRYPTO_STORAGE_C', # requires a filesystem
|
||||
'MBEDTLS_PSA_ITS_FILE_C', # requires a filesystem
|
||||
'MBEDTLS_THREADING_C', # requires a threading interface
|
||||
'MBEDTLS_THREADING_PTHREAD', # requires pthread
|
||||
'MBEDTLS_TIMING_C', # requires a clock
|
||||
'MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT', # requires an OS for runtime-detection
|
||||
'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT', # requires an OS for runtime-detection
|
||||
'MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT', # requires an OS for runtime-detection
|
||||
])
|
||||
|
||||
def keep_in_baremetal(name):
|
||||
"""Rules for symbols in the "baremetal" configuration."""
|
||||
if name in EXCLUDE_FROM_BAREMETAL:
|
||||
return False
|
||||
return True
|
||||
|
||||
def baremetal_adapter(name, value, active):
|
||||
"""Config adapter for "baremetal"."""
|
||||
if not is_boolean_setting(name, value):
|
||||
return active
|
||||
if name == 'MBEDTLS_NO_PLATFORM_ENTROPY':
|
||||
# No OS-provided entropy source
|
||||
return True
|
||||
return include_in_full(name) and keep_in_baremetal(name)
|
||||
|
||||
# This set contains options that are mostly for debugging or test purposes,
|
||||
# and therefore should be excluded when doing code size measurements.
|
||||
# Options that are their own module (such as MBEDTLS_ERROR_C) are not listed
|
||||
# and therefore will be included when doing code size measurements.
|
||||
EXCLUDE_FOR_SIZE = frozenset([
|
||||
'MBEDTLS_DEBUG_C', # large code size increase in TLS
|
||||
'MBEDTLS_SELF_TEST', # increases the size of many modules
|
||||
'MBEDTLS_TEST_HOOKS', # only useful with the hosted test framework, increases code size
|
||||
])
|
||||
|
||||
def baremetal_size_adapter(name, value, active):
|
||||
if name in EXCLUDE_FOR_SIZE:
|
||||
return False
|
||||
return baremetal_adapter(name, value, active)
|
||||
|
||||
def include_in_crypto(name):
|
||||
"""Rules for symbols in a crypto configuration."""
|
||||
if name.startswith('MBEDTLS_X509_') or \
|
||||
name.startswith('MBEDTLS_SSL_') or \
|
||||
name.startswith('MBEDTLS_KEY_EXCHANGE_'):
|
||||
return False
|
||||
if name in [
|
||||
'MBEDTLS_DEBUG_C', # part of libmbedtls
|
||||
'MBEDTLS_NET_C', # part of libmbedtls
|
||||
'MBEDTLS_PKCS7_C', # part of libmbedx509
|
||||
]:
|
||||
return False
|
||||
if name in EXCLUDE_FROM_CRYPTO:
|
||||
return False
|
||||
return True
|
||||
|
||||
def crypto_adapter(adapter):
|
||||
"""Modify an adapter to disable non-crypto symbols.
|
||||
|
||||
``crypto_adapter(adapter)(name, value, active)`` is like
|
||||
``adapter(name, value, active)``, but unsets all X.509 and TLS symbols.
|
||||
"""
|
||||
def continuation(name, value, active):
|
||||
if not include_in_crypto(name):
|
||||
return False
|
||||
if adapter is None:
|
||||
return active
|
||||
return adapter(name, value, active)
|
||||
return continuation
|
||||
|
||||
DEPRECATED = frozenset([
|
||||
'MBEDTLS_PSA_CRYPTO_SE_C',
|
||||
*PSA_DEPRECATED_FEATURE
|
||||
])
|
||||
def no_deprecated_adapter(adapter):
|
||||
"""Modify an adapter to disable deprecated symbols.
|
||||
|
||||
``no_deprecated_adapter(adapter)(name, value, active)`` is like
|
||||
``adapter(name, value, active)``, but unsets all deprecated symbols
|
||||
and sets ``MBEDTLS_DEPRECATED_REMOVED``.
|
||||
"""
|
||||
def continuation(name, value, active):
|
||||
if name == 'MBEDTLS_DEPRECATED_REMOVED':
|
||||
return True
|
||||
if name in DEPRECATED:
|
||||
return False
|
||||
if adapter is None:
|
||||
return active
|
||||
return adapter(name, value, active)
|
||||
return continuation
|
||||
|
||||
def no_platform_adapter(adapter):
|
||||
"""Modify an adapter to disable platform symbols.
|
||||
|
||||
``no_platform_adapter(adapter)(name, value, active)`` is like
|
||||
``adapter(name, value, active)``, but unsets all platform symbols other
|
||||
``than MBEDTLS_PLATFORM_C.
|
||||
"""
|
||||
def continuation(name, value, active):
|
||||
# Allow MBEDTLS_PLATFORM_C but remove all other platform symbols.
|
||||
if name.startswith('MBEDTLS_PLATFORM_') and name != 'MBEDTLS_PLATFORM_C':
|
||||
return False
|
||||
if adapter is None:
|
||||
return active
|
||||
return adapter(name, value, active)
|
||||
return continuation
|
||||
|
||||
|
||||
class MbedTLSConfigFile(config_common.ConfigFile):
|
||||
"""Representation of an MbedTLS configuration file."""
|
||||
|
||||
_path_in_tree = 'include/mbedtls/mbedtls_config.h'
|
||||
default_path = [_path_in_tree,
|
||||
os.path.join(os.path.dirname(__file__),
|
||||
os.pardir,
|
||||
_path_in_tree),
|
||||
os.path.join(os.path.dirname(os.path.abspath(os.path.dirname(__file__))),
|
||||
_path_in_tree)]
|
||||
|
||||
def __init__(self, filename=None):
|
||||
super().__init__(self.default_path, 'Mbed TLS', filename)
|
||||
self.current_section = 'header'
|
||||
|
||||
|
||||
class CryptoConfigFile(config_common.ConfigFile):
|
||||
"""Representation of a Crypto configuration file."""
|
||||
|
||||
# Temporary, while Mbed TLS does not just rely on the TF-PSA-Crypto
|
||||
# build system to build its crypto library. When it does, the
|
||||
# condition can just be removed.
|
||||
_path_in_tree = ('include/psa/crypto_config.h'
|
||||
if not os.path.isdir(os.path.join(os.path.dirname(__file__),
|
||||
os.pardir,
|
||||
'tf-psa-crypto')) else
|
||||
'tf-psa-crypto/include/psa/crypto_config.h')
|
||||
default_path = [_path_in_tree,
|
||||
os.path.join(os.path.dirname(__file__),
|
||||
os.pardir,
|
||||
_path_in_tree),
|
||||
os.path.join(os.path.dirname(os.path.abspath(os.path.dirname(__file__))),
|
||||
_path_in_tree)]
|
||||
|
||||
def __init__(self, filename=None):
|
||||
super().__init__(self.default_path, 'Crypto', filename)
|
||||
|
||||
|
||||
class MbedTLSConfig(config_common.Config):
|
||||
"""Representation of the Mbed TLS configuration.
|
||||
|
||||
See the documentation of the `Config` class for methods to query
|
||||
and modify the configuration.
|
||||
"""
|
||||
|
||||
def __init__(self, filename=None):
|
||||
"""Read the Mbed TLS configuration file."""
|
||||
|
||||
super().__init__()
|
||||
configfile = MbedTLSConfigFile(filename)
|
||||
self.configfiles.append(configfile)
|
||||
self.settings.update({name: config_common.Setting(configfile, active, name, value, section)
|
||||
for (active, name, value, section)
|
||||
in configfile.parse_file()})
|
||||
|
||||
def set(self, name, value=None):
|
||||
"""Set name to the given value and make it active."""
|
||||
|
||||
if name not in self.settings:
|
||||
self._get_configfile().templates.append((name, '', '#define ' + name + ' '))
|
||||
|
||||
super().set(name, value)
|
||||
|
||||
|
||||
class CryptoConfig(config_common.Config):
|
||||
"""Representation of the PSA crypto configuration.
|
||||
|
||||
See the documentation of the `Config` class for methods to query
|
||||
and modify the configuration.
|
||||
"""
|
||||
|
||||
def __init__(self, filename=None):
|
||||
"""Read the PSA crypto configuration file."""
|
||||
|
||||
super().__init__()
|
||||
configfile = CryptoConfigFile(filename)
|
||||
self.configfiles.append(configfile)
|
||||
self.settings.update({name: config_common.Setting(configfile, active, name, value, section)
|
||||
for (active, name, value, section)
|
||||
in configfile.parse_file()})
|
||||
|
||||
def set(self, name, value='1'):
|
||||
"""Set name to the given value and make it active."""
|
||||
|
||||
if name in PSA_UNSUPPORTED_FEATURE:
|
||||
raise ValueError(f'Feature is unsupported: \'{name}\'')
|
||||
if name in PSA_UNSTABLE_FEATURE:
|
||||
raise ValueError(f'Feature is unstable: \'{name}\'')
|
||||
|
||||
if name not in self.settings:
|
||||
self._get_configfile().templates.append((name, '', '#define ' + name + ' '))
|
||||
|
||||
super().set(name, value)
|
||||
|
||||
|
||||
class CombinedConfig(config_common.Config):
|
||||
"""Representation of MbedTLS and PSA crypto configuration
|
||||
|
||||
See the documentation of the `Config` class for methods to query
|
||||
and modify the configuration.
|
||||
"""
|
||||
|
||||
def __init__(self, *configs):
|
||||
super().__init__()
|
||||
for config in configs:
|
||||
if isinstance(config, MbedTLSConfigFile):
|
||||
self.mbedtls_configfile = config
|
||||
elif isinstance(config, CryptoConfigFile):
|
||||
self.crypto_configfile = config
|
||||
else:
|
||||
raise ValueError(f'Invalid configfile: {config}')
|
||||
self.configfiles.append(config)
|
||||
|
||||
self.settings.update({name: config_common.Setting(configfile, active, name, value, section)
|
||||
for configfile in [self.mbedtls_configfile, self.crypto_configfile]
|
||||
for (active, name, value, section) in configfile.parse_file()})
|
||||
|
||||
_crypto_regexp = re.compile(r'$PSA_.*')
|
||||
def _get_configfile(self, name=None):
|
||||
"""Find a config type for a setting name"""
|
||||
|
||||
if name in self.settings:
|
||||
return self.settings[name].configfile
|
||||
elif re.match(self._crypto_regexp, name):
|
||||
return self.crypto_configfile
|
||||
else:
|
||||
return self.mbedtls_configfile
|
||||
|
||||
def set(self, name, value=None):
|
||||
"""Set name to the given value and make it active."""
|
||||
|
||||
configfile = self._get_configfile(name)
|
||||
|
||||
if configfile == self.crypto_configfile:
|
||||
if name in PSA_UNSUPPORTED_FEATURE:
|
||||
raise ValueError(f'Feature is unsupported: \'{name}\'')
|
||||
if name in PSA_UNSTABLE_FEATURE:
|
||||
raise ValueError(f'Feature is unstable: \'{name}\'')
|
||||
|
||||
# The default value in the crypto config is '1'
|
||||
if not value:
|
||||
value = '1'
|
||||
|
||||
if name not in self.settings:
|
||||
configfile.templates.append((name, '', '#define ' + name + ' '))
|
||||
|
||||
super().set(name, value)
|
||||
|
||||
#pylint: disable=arguments-differ
|
||||
def write(self, mbedtls_file=None, crypto_file=None):
|
||||
"""Write the whole configuration to the file it was read from.
|
||||
|
||||
If mbedtls_file or crypto_file is specified, write the specific configuration
|
||||
to the corresponding file instead.
|
||||
|
||||
Two file name parameters and not only one as in the super class as we handle
|
||||
two configuration files in this class.
|
||||
"""
|
||||
|
||||
self.mbedtls_configfile.write(self.settings, mbedtls_file)
|
||||
self.crypto_configfile.write(self.settings, crypto_file)
|
||||
|
||||
def filename(self, name=None):
|
||||
"""Get the name of the config files.
|
||||
|
||||
If 'name' is specified return the name of the config file where it is defined.
|
||||
"""
|
||||
|
||||
if not name:
|
||||
return [config.filename for config in [self.mbedtls_configfile, self.crypto_configfile]]
|
||||
|
||||
return self._get_configfile(name).filename
|
||||
|
||||
|
||||
class MbedTLSConfigTool(config_common.ConfigTool):
|
||||
"""Command line mbedtls_config.h and crypto_config.h manipulation tool."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(MbedTLSConfigFile.default_path)
|
||||
self.config = CombinedConfig(MbedTLSConfigFile(self.args.file),
|
||||
CryptoConfigFile(self.args.cryptofile))
|
||||
|
||||
def custom_parser_options(self):
|
||||
"""Adds MbedTLS specific options for the parser."""
|
||||
|
||||
self.parser.add_argument(
|
||||
'--cryptofile', '-c',
|
||||
help="""Crypto file to read (and modify if requested). Default: {}."""
|
||||
.format(CryptoConfigFile.default_path))
|
||||
|
||||
self.add_adapter(
|
||||
'baremetal', baremetal_adapter,
|
||||
"""Like full, but exclude features that require platform features
|
||||
such as file input-output.
|
||||
""")
|
||||
self.add_adapter(
|
||||
'baremetal_size', baremetal_size_adapter,
|
||||
"""Like baremetal, but exclude debugging features. Useful for code size measurements.
|
||||
""")
|
||||
self.add_adapter(
|
||||
'full', full_adapter,
|
||||
"""Uncomment most features.
|
||||
Exclude alternative implementations and platform support options, as well as
|
||||
some options that are awkward to test.
|
||||
""")
|
||||
self.add_adapter(
|
||||
'full_no_deprecated', no_deprecated_adapter(full_adapter),
|
||||
"""Uncomment most non-deprecated features.
|
||||
Like "full", but without deprecated features.
|
||||
""")
|
||||
self.add_adapter(
|
||||
'full_no_platform', no_platform_adapter(full_adapter),
|
||||
"""Uncomment most non-platform features. Like "full", but without platform features.
|
||||
""")
|
||||
self.add_adapter(
|
||||
'realfull', realfull_adapter,
|
||||
"""Uncomment all boolean #defines.
|
||||
Suitable for generating documentation, but not for building.
|
||||
""")
|
||||
self.add_adapter(
|
||||
'crypto', crypto_adapter(None),
|
||||
"""Only include crypto features. Exclude X.509 and TLS.""")
|
||||
self.add_adapter(
|
||||
'crypto_baremetal', crypto_adapter(baremetal_adapter),
|
||||
"""Like baremetal, but with only crypto features, excluding X.509 and TLS.""")
|
||||
self.add_adapter(
|
||||
'crypto_full', crypto_adapter(full_adapter),
|
||||
"""Like full, but with only crypto features, excluding X.509 and TLS.""")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(MbedTLSConfigTool().main())
|
||||
@@ -1,71 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"prefix": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": ["opaque"]
|
||||
},
|
||||
"location": {
|
||||
"type": ["integer","string"],
|
||||
"pattern": "^(0x|0X)?[a-fA-F0-9]+$"
|
||||
},
|
||||
"mbedtls/h_condition": {
|
||||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"mbedtls/c_condition": {
|
||||
"type": "string"
|
||||
},
|
||||
"entry_points": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"names": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[A-Z_a-z][0-9A-Z_a-z]*$": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entry_points"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"prefix",
|
||||
"type",
|
||||
"location",
|
||||
"capabilities"
|
||||
]
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"prefix": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": ["transparent"]
|
||||
},
|
||||
"mbedtls/h_condition": {
|
||||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"mbedtls/c_condition": {
|
||||
"type": "string"
|
||||
},
|
||||
"entry_points": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"names": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[A-Z_a-z][0-9A-Z_a-z]*$": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fallback": {
|
||||
"type": "boolean",
|
||||
"default": "false"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entry_points"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"prefix",
|
||||
"type",
|
||||
"capabilities"
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
["mbedtls_test_opaque_driver.json","mbedtls_test_transparent_driver.json","p256_transparent_driver.json"]
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"prefix": "mbedtls_test",
|
||||
"type": "opaque",
|
||||
"location": "0x7fffff",
|
||||
"mbedtls/h_condition": "defined(PSA_CRYPTO_DRIVER_TEST)",
|
||||
"headers": ["test/drivers/test_driver.h"],
|
||||
"capabilities": [
|
||||
{
|
||||
"_comment": "The Mbed TLS opaque driver supports import key/export key/export_public key",
|
||||
"mbedtls/c_condition": "defined(PSA_CRYPTO_DRIVER_TEST)",
|
||||
"entry_points": ["import_key", "export_key", "export_public_key"]
|
||||
},
|
||||
{
|
||||
"_comment": "The Mbed TLS opaque driver supports copy key/ get builtin key",
|
||||
"mbedtls/c_condition": "defined(PSA_CRYPTO_DRIVER_TEST)",
|
||||
"entry_points": ["copy_key", "get_builtin_key"],
|
||||
"names": {"copy_key":"mbedtls_test_opaque_copy_key", "get_builtin_key":"mbedtls_test_opaque_get_builtin_key"}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"prefix": "mbedtls_test",
|
||||
"type": "transparent",
|
||||
"mbedtls/h_condition": "defined(PSA_CRYPTO_DRIVER_TEST)",
|
||||
"headers": ["test/drivers/test_driver.h"],
|
||||
"capabilities": [
|
||||
{
|
||||
"_comment": "The Mbed TLS transparent driver supports import key/export key",
|
||||
"mbedtls/c_condition": "defined(PSA_CRYPTO_DRIVER_TEST)",
|
||||
"entry_points": ["import_key"],
|
||||
"fallback": true
|
||||
},
|
||||
{
|
||||
"_comment": "The Mbed TLS transparent driver supports export_public key",
|
||||
"mbedtls/c_condition": "defined(PSA_CRYPTO_DRIVER_TEST)",
|
||||
"entry_points": ["export_public_key"],
|
||||
"fallback": true,
|
||||
"names": {"export_public_key":"mbedtls_test_transparent_export_public_key"}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"prefix": "p256",
|
||||
"type": "transparent",
|
||||
"mbedtls/h_condition": "defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)",
|
||||
"headers": ["../tf-psa-crypto/drivers/p256-m/p256-m_driver_entrypoints.h"],
|
||||
"capabilities": [
|
||||
{
|
||||
"mbedtls/c_condition": "defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)",
|
||||
"_comment_entry_points": "This is not the complete list of entry points supported by this driver, only those that are currently supported in JSON. See docs/psa-driver-example-and-guide.md",
|
||||
"entry_points": ["import_key", "export_public_key"],
|
||||
"algorithms": ["PSA_ALG_ECDH", "PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)"],
|
||||
"key_types": [
|
||||
"PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)",
|
||||
"PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)"
|
||||
],
|
||||
"key_sizes": [256],
|
||||
"fallback": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{# One Shot function's dispatch code for opaque drivers.
|
||||
Expected inputs:
|
||||
* drivers: the list of driver descriptions.
|
||||
* entry_point: the name of the entry point that this function dispatches to.
|
||||
* entry_point_param(driver): the parameters to pass to the entry point.
|
||||
* nest_indent: number of extra spaces to indent the code to.
|
||||
-#}
|
||||
{% for driver in drivers if driver.type == "opaque" -%}
|
||||
{% for capability in driver.capabilities if entry_point in capability.entry_points -%}
|
||||
#if ({% if capability['mbedtls/c_condition'] is defined -%}{{ capability['mbedtls/c_condition'] }} {% else -%} {{ 1 }} {% endif %})
|
||||
{%- filter indent(width = nest_indent) %}
|
||||
case {{ driver.location }}:
|
||||
return( {{ entry_point_name(capability, entry_point, driver) }}({{entry_point_param(driver) | indent(20)}}));
|
||||
{% endfilter -%}
|
||||
#endif
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
@@ -1,19 +0,0 @@
|
||||
{# One Shot function's dispatch code for transparent drivers.
|
||||
Expected inputs:
|
||||
* drivers: the list of driver descriptions.
|
||||
* entry_point: the name of the entry point that this function dispatches to.
|
||||
* entry_point_param(driver): the parameters to pass to the entry point.
|
||||
* nest_indent: number of extra spaces to indent the code to.
|
||||
-#}
|
||||
{% for driver in drivers if driver.type == "transparent" -%}
|
||||
{% for capability in driver.capabilities if entry_point in capability.entry_points -%}
|
||||
#if ({% if capability['mbedtls/c_condition'] is defined -%}{{ capability['mbedtls/c_condition'] }} {% else -%} {{ 1 }} {% endif %})
|
||||
{%- filter indent(width = nest_indent) %}
|
||||
status = {{ entry_point_name(capability, entry_point, driver) }}({{entry_point_param(driver) | indent(20)}});
|
||||
|
||||
if( status != PSA_ERROR_NOT_SUPPORTED )
|
||||
return( status );
|
||||
{% endfilter -%}
|
||||
#endif
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Functions to delegate cryptographic operations to an available
|
||||
* and appropriate accelerator.
|
||||
* Warning: This file is now auto-generated.
|
||||
*/
|
||||
/* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
|
||||
/* BEGIN-common headers */
|
||||
#include "common.h"
|
||||
#include "psa_crypto_aead.h"
|
||||
#include "psa_crypto_cipher.h"
|
||||
#include "psa_crypto_core.h"
|
||||
#include "psa_crypto_driver_wrappers_no_static.h"
|
||||
#include "psa_crypto_hash.h"
|
||||
#include "psa_crypto_mac.h"
|
||||
#include "psa_crypto_pake.h"
|
||||
#include "psa_crypto_rsa.h"
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
/* END-common headers */
|
||||
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_C)
|
||||
|
||||
/* BEGIN-driver headers */
|
||||
{% for driver in drivers -%}
|
||||
/* Headers for {{driver.prefix}} {{driver.type}} driver */
|
||||
{% if driver['mbedtls/h_condition'] is defined -%}
|
||||
#if {{ driver['mbedtls/h_condition'] }}
|
||||
{% endif -%}
|
||||
{% for header in driver.headers -%}
|
||||
#include "{{ header }}"
|
||||
{% endfor %}
|
||||
{% if driver['mbedtls/h_condition'] is defined -%}
|
||||
#endif
|
||||
{% endif -%}
|
||||
{% endfor %}
|
||||
/* END-driver headers */
|
||||
|
||||
/* Auto-generated values depending on which drivers are registered.
|
||||
* ID 0 is reserved for unallocated operations.
|
||||
* ID 1 is reserved for the Mbed TLS software driver. */
|
||||
/* BEGIN-driver id definition */
|
||||
#define PSA_CRYPTO_MBED_TLS_DRIVER_ID (1)
|
||||
{% for driver in drivers -%}
|
||||
#define {{(driver.prefix + "_" + driver.type + "_driver_id").upper()}} ({{ loop.index + 1 }})
|
||||
{% endfor %}
|
||||
/* END-driver id */
|
||||
|
||||
/* BEGIN-Common Macro definitions */
|
||||
{% macro entry_point_name(capability, entry_point, driver) -%}
|
||||
{% if capability.name is defined and entry_point in capability.names.keys() -%}
|
||||
{{ capability.names[entry_point]}}
|
||||
{% else -%}
|
||||
{{driver.prefix}}_{{driver.type}}_{{entry_point}}
|
||||
{% endif -%}
|
||||
{% endmacro %}
|
||||
/* END-Common Macro definitions */
|
||||
|
||||
/* Support the 'old' SE interface when asked to */
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
/* PSA_CRYPTO_DRIVER_PRESENT is defined when either a new-style or old-style
|
||||
* SE driver is present, to avoid unused argument errors at compile time. */
|
||||
#ifndef PSA_CRYPTO_DRIVER_PRESENT
|
||||
#define PSA_CRYPTO_DRIVER_PRESENT
|
||||
#endif
|
||||
#include "psa_crypto_se.h"
|
||||
#endif
|
||||
|
||||
/** Get the key buffer size required to store the key material of a key
|
||||
* associated with an opaque driver.
|
||||
*
|
||||
* \param[in] attributes The key attributes.
|
||||
* \param[out] key_buffer_size Minimum buffer size to contain the key material
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* The minimum size for a buffer to contain the key material has been
|
||||
* returned successfully.
|
||||
* \retval #PSA_ERROR_NOT_SUPPORTED
|
||||
* The type and/or the size in bits of the key or the combination of
|
||||
* the two is not supported.
|
||||
* \retval #PSA_ERROR_INVALID_ARGUMENT
|
||||
* The key is declared with a lifetime not known to us.
|
||||
*/
|
||||
psa_status_t psa_driver_wrapper_get_key_buffer_size(
|
||||
const psa_key_attributes_t *attributes,
|
||||
size_t *key_buffer_size )
|
||||
{
|
||||
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
|
||||
psa_key_type_t key_type = psa_get_key_type(attributes);
|
||||
size_t key_bits = psa_get_key_bits(attributes);
|
||||
|
||||
*key_buffer_size = 0;
|
||||
switch( location )
|
||||
{
|
||||
#if defined(PSA_CRYPTO_DRIVER_TEST)
|
||||
case PSA_CRYPTO_TEST_DRIVER_LOCATION:
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
|
||||
/* Emulate property 'builtin_key_size' */
|
||||
if( psa_key_id_is_builtin(
|
||||
MBEDTLS_SVC_KEY_ID_GET_KEY_ID(
|
||||
psa_get_key_id( attributes ) ) ) )
|
||||
{
|
||||
*key_buffer_size = sizeof( psa_drv_slot_number_t );
|
||||
return( PSA_SUCCESS );
|
||||
}
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
|
||||
*key_buffer_size = mbedtls_test_opaque_size_function( key_type,
|
||||
key_bits );
|
||||
return( ( *key_buffer_size != 0 ) ?
|
||||
PSA_SUCCESS : PSA_ERROR_NOT_SUPPORTED );
|
||||
#endif /* PSA_CRYPTO_DRIVER_TEST */
|
||||
|
||||
default:
|
||||
(void)key_type;
|
||||
(void)key_bits;
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
}
|
||||
}
|
||||
|
||||
psa_status_t psa_driver_wrapper_export_public_key(
|
||||
const psa_key_attributes_t *attributes,
|
||||
const uint8_t *key_buffer, size_t key_buffer_size,
|
||||
uint8_t *data, size_t data_size, size_t *data_length )
|
||||
|
||||
{
|
||||
{% with entry_point = "export_public_key" -%}
|
||||
{% macro entry_point_param(driver) -%}
|
||||
attributes,
|
||||
key_buffer,
|
||||
key_buffer_size,
|
||||
data,
|
||||
data_size,
|
||||
data_length
|
||||
{% endmacro %}
|
||||
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
|
||||
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(
|
||||
psa_get_key_lifetime( attributes ) );
|
||||
|
||||
/* Try dynamically-registered SE interface first */
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
|
||||
const psa_drv_se_t *drv;
|
||||
psa_drv_se_context_t *drv_context;
|
||||
|
||||
if( psa_get_se_driver( psa_get_key_lifetime(attributes), &drv, &drv_context ) )
|
||||
{
|
||||
if( ( drv->key_management == NULL ) ||
|
||||
( drv->key_management->p_export_public == NULL ) )
|
||||
{
|
||||
return( PSA_ERROR_NOT_SUPPORTED );
|
||||
}
|
||||
|
||||
return( drv->key_management->p_export_public(
|
||||
drv_context,
|
||||
*( (psa_key_slot_number_t *)key_buffer ),
|
||||
data, data_size, data_length ) );
|
||||
}
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
|
||||
|
||||
switch( location )
|
||||
{
|
||||
case PSA_KEY_LOCATION_LOCAL_STORAGE:
|
||||
/* Key is stored in the slot in export representation, so
|
||||
* cycle through all known transparent accelerators */
|
||||
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
|
||||
{% with nest_indent=12 %}
|
||||
{% include "OS-template-transparent.jinja" -%}
|
||||
{% endwith -%}
|
||||
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
|
||||
/* Fell through, meaning no accelerator supports this operation */
|
||||
return( psa_export_public_key_internal( attributes,
|
||||
key_buffer,
|
||||
key_buffer_size,
|
||||
data,
|
||||
data_size,
|
||||
data_length ) );
|
||||
|
||||
/* Add cases for opaque driver here */
|
||||
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
|
||||
{% with nest_indent=8 %}
|
||||
{% include "OS-template-opaque.jinja" -%}
|
||||
{% endwith -%}
|
||||
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
|
||||
default:
|
||||
/* Key is declared with a lifetime not known to us */
|
||||
return( status );
|
||||
}
|
||||
{% endwith %}
|
||||
}
|
||||
|
||||
psa_status_t psa_driver_wrapper_get_builtin_key(
|
||||
psa_drv_slot_number_t slot_number,
|
||||
psa_key_attributes_t *attributes,
|
||||
uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length )
|
||||
{
|
||||
{% with entry_point = "get_builtin_key" -%}
|
||||
{% macro entry_point_param(driver) -%}
|
||||
slot_number,
|
||||
attributes,
|
||||
key_buffer,
|
||||
key_buffer_size,
|
||||
key_buffer_length
|
||||
{% endmacro %}
|
||||
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
|
||||
switch( location )
|
||||
{
|
||||
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
|
||||
{% with nest_indent=8 %}
|
||||
{% include "OS-template-opaque.jinja" -%}
|
||||
{% endwith -%}
|
||||
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
|
||||
default:
|
||||
(void) slot_number;
|
||||
(void) key_buffer;
|
||||
(void) key_buffer_size;
|
||||
(void) key_buffer_length;
|
||||
return( PSA_ERROR_DOES_NOT_EXIST );
|
||||
}
|
||||
{% endwith %}
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_C */
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Error message information
|
||||
*
|
||||
* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "mbedtls/error.h"
|
||||
|
||||
#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY)
|
||||
|
||||
#if defined(MBEDTLS_ERROR_C)
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
HEADER_INCLUDED
|
||||
|
||||
const char *mbedtls_high_level_strerr(int error_code)
|
||||
{
|
||||
int high_level_error_code;
|
||||
|
||||
if (error_code < 0) {
|
||||
error_code = -error_code;
|
||||
}
|
||||
|
||||
/* Extract the high-level part from the error code. */
|
||||
high_level_error_code = error_code & 0xFF80;
|
||||
|
||||
switch (high_level_error_code) {
|
||||
/* Begin Auto-Generated Code. */
|
||||
HIGH_LEVEL_CODE_CHECKS
|
||||
/* End Auto-Generated Code. */
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *mbedtls_low_level_strerr(int error_code)
|
||||
{
|
||||
int low_level_error_code;
|
||||
|
||||
if (error_code < 0) {
|
||||
error_code = -error_code;
|
||||
}
|
||||
|
||||
/* Extract the low-level part from the error code. */
|
||||
low_level_error_code = error_code & ~0xFF80;
|
||||
|
||||
switch (low_level_error_code) {
|
||||
/* Begin Auto-Generated Code. */
|
||||
LOW_LEVEL_CODE_CHECKS
|
||||
/* End Auto-Generated Code. */
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mbedtls_strerror(int ret, char *buf, size_t buflen)
|
||||
{
|
||||
size_t len;
|
||||
int use_ret;
|
||||
const char *high_level_error_description = NULL;
|
||||
const char *low_level_error_description = NULL;
|
||||
|
||||
if (buflen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buf, 0x00, buflen);
|
||||
|
||||
if (ret < 0) {
|
||||
ret = -ret;
|
||||
}
|
||||
|
||||
if (ret & 0xFF80) {
|
||||
use_ret = ret & 0xFF80;
|
||||
|
||||
// Translate high level error code.
|
||||
high_level_error_description = mbedtls_high_level_strerr(ret);
|
||||
|
||||
if (high_level_error_description == NULL) {
|
||||
mbedtls_snprintf(buf, buflen, "UNKNOWN ERROR CODE (%04X)", (unsigned int) use_ret);
|
||||
} else {
|
||||
mbedtls_snprintf(buf, buflen, "%s", high_level_error_description);
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_TLS_C)
|
||||
// Early return in case of a fatal error - do not try to translate low
|
||||
// level code.
|
||||
if (use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE)) {
|
||||
return;
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_TLS_C */
|
||||
}
|
||||
|
||||
use_ret = ret & ~0xFF80;
|
||||
|
||||
if (use_ret == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If high level code is present, make a concatenation between both
|
||||
// error strings.
|
||||
//
|
||||
len = strlen(buf);
|
||||
|
||||
if (len > 0) {
|
||||
if (buflen - len < 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
mbedtls_snprintf(buf + len, buflen - len, " : ");
|
||||
|
||||
buf += len + 3;
|
||||
buflen -= len + 3;
|
||||
}
|
||||
|
||||
// Translate low level error code.
|
||||
low_level_error_description = mbedtls_low_level_strerr(ret);
|
||||
|
||||
if (low_level_error_description == NULL) {
|
||||
mbedtls_snprintf(buf, buflen, "UNKNOWN ERROR CODE (%04X)", (unsigned int) use_ret);
|
||||
} else {
|
||||
mbedtls_snprintf(buf, buflen, "%s", low_level_error_description);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* MBEDTLS_ERROR_C */
|
||||
|
||||
/*
|
||||
* Provide a dummy implementation when MBEDTLS_ERROR_C is not defined
|
||||
*/
|
||||
void mbedtls_strerror(int ret, char *buf, size_t buflen)
|
||||
{
|
||||
((void) ret);
|
||||
|
||||
if (buflen > 0) {
|
||||
buf[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_ERROR_C */
|
||||
|
||||
#if defined(MBEDTLS_TEST_HOOKS)
|
||||
void (*mbedtls_test_hook_error_add)(int, int, const char *, int);
|
||||
#endif
|
||||
|
||||
#endif /* MBEDTLS_ERROR_C || MBEDTLS_ERROR_STRERROR_DUMMY */
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Query Mbed TLS compile time configurations from mbedtls_config.h
|
||||
*
|
||||
* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "mbedtls/build_info.h"
|
||||
|
||||
#include "query_config.h"
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
|
||||
/*
|
||||
* Include all the headers with public APIs in case they define a macro to its
|
||||
* default value when that configuration is not set in mbedtls_config.h, or
|
||||
* for PSA_WANT macros, in case they're auto-defined based on mbedtls_config.h
|
||||
* rather than defined directly in crypto_config.h.
|
||||
*/
|
||||
#include "psa/crypto.h"
|
||||
|
||||
#include "mbedtls/aes.h"
|
||||
#include "mbedtls/aria.h"
|
||||
#include "mbedtls/asn1.h"
|
||||
#include "mbedtls/asn1write.h"
|
||||
#include "mbedtls/base64.h"
|
||||
#include "mbedtls/bignum.h"
|
||||
#include "mbedtls/camellia.h"
|
||||
#include "mbedtls/ccm.h"
|
||||
#include "mbedtls/chacha20.h"
|
||||
#include "mbedtls/chachapoly.h"
|
||||
#include "mbedtls/cipher.h"
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/des.h"
|
||||
#include "mbedtls/dhm.h"
|
||||
#include "mbedtls/ecdh.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "mbedtls/ecjpake.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/gcm.h"
|
||||
#include "mbedtls/hkdf.h"
|
||||
#include "mbedtls/hmac_drbg.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/md5.h"
|
||||
#include "mbedtls/memory_buffer_alloc.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/nist_kw.h"
|
||||
#include "mbedtls/oid.h"
|
||||
#include "mbedtls/pem.h"
|
||||
#include "mbedtls/pk.h"
|
||||
#include "mbedtls/pkcs12.h"
|
||||
#include "mbedtls/pkcs5.h"
|
||||
#if defined(MBEDTLS_HAVE_TIME)
|
||||
#include "mbedtls/platform_time.h"
|
||||
#endif
|
||||
#include "mbedtls/platform_util.h"
|
||||
#include "mbedtls/poly1305.h"
|
||||
#include "mbedtls/ripemd160.h"
|
||||
#include "mbedtls/rsa.h"
|
||||
#include "mbedtls/sha1.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/sha512.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/ssl_cache.h"
|
||||
#include "mbedtls/ssl_ciphersuites.h"
|
||||
#include "mbedtls/ssl_cookie.h"
|
||||
#include "mbedtls/ssl_ticket.h"
|
||||
#include "mbedtls/threading.h"
|
||||
#include "mbedtls/timing.h"
|
||||
#include "mbedtls/version.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/x509_crl.h"
|
||||
#include "mbedtls/x509_crt.h"
|
||||
#include "mbedtls/x509_csr.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Helper macros to convert a macro or its expansion into a string
|
||||
* WARNING: This does not work for expanding function-like macros. However,
|
||||
* Mbed TLS does not currently have configuration options used in this fashion.
|
||||
*/
|
||||
#define MACRO_EXPANSION_TO_STR(macro) MACRO_NAME_TO_STR(macro)
|
||||
#define MACRO_NAME_TO_STR(macro) \
|
||||
mbedtls_printf("%s", strlen( #macro "") > 0 ? #macro "\n" : "")
|
||||
|
||||
#define STRINGIFY(macro) #macro
|
||||
#define OUTPUT_MACRO_NAME_VALUE(macro) mbedtls_printf( #macro "%s\n", \
|
||||
(STRINGIFY(macro) "")[0] != 0 ? "=" STRINGIFY( \
|
||||
macro) : "")
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/*
|
||||
* Visual Studio throws the warning 4003 because many Mbed TLS feature macros
|
||||
* are defined empty. This means that from the preprocessor's point of view
|
||||
* the macro MBEDTLS_EXPANSION_TO_STR is being invoked without arguments as
|
||||
* some macros expand to nothing. We suppress that specific warning to get a
|
||||
* clean build and to ensure that tests treating warnings as errors do not
|
||||
* fail.
|
||||
*/
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4003)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
int query_config(const char *config)
|
||||
{
|
||||
CHECK_CONFIG /* If the symbol is not found, return an error */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void list_config(void)
|
||||
{
|
||||
LIST_CONFIG
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif /* _MSC_VER */
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Version feature information
|
||||
*
|
||||
* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(MBEDTLS_VERSION_C)
|
||||
|
||||
#include "mbedtls/version.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static const char * const features[] = {
|
||||
#if defined(MBEDTLS_VERSION_FEATURES)
|
||||
FEATURE_DEFINES
|
||||
#endif /* MBEDTLS_VERSION_FEATURES */
|
||||
NULL
|
||||
};
|
||||
|
||||
int mbedtls_version_check_feature(const char *feature)
|
||||
{
|
||||
const char * const *idx = features;
|
||||
|
||||
if (*idx == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (feature == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp(feature, "MBEDTLS_", 8)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
feature += 8;
|
||||
|
||||
while (*idx != NULL) {
|
||||
if (!strcmp(*idx, feature)) {
|
||||
return 0;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_VERSION_C */
|
||||
@@ -1,175 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<SOURCES>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="mbedTLS.vcxproj">
|
||||
<Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid><GUID></ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace><APPNAME></RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>false</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>false</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,163 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{46CF2D25-6A36-4189-B59C-E4815388E554}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>mbedTLS</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>$(Configuration)\$(TargetName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_USRDLL;MBEDTLS_EXPORTS;KRML_VERIFIED_UINT128;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
<CompileAs>CompileAsC</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_USRDLL;MBEDTLS_EXPORTS;KRML_VERIFIED_UINT128;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
<CompileAs>CompileAsC</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_USRDLL;MBEDTLS_EXPORTS;KRML_VERIFIED_UINT128;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;MBEDTLS_EXPORTS;KRML_VERIFIED_UINT128;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
INCLUDE_DIRECTORIES
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
HEADER_ENTRIES
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
SOURCE_ENTRIES
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2017
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
MinimumVisualStudioVersion = 15.0.26228.4
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mbedTLS", "mbedTLS.vcxproj", "{46CF2D25-6A36-4189-B59C-E4815388E554}"
|
||||
EndProject
|
||||
APP_ENTRIES
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Debug|x64.Build.0 = Debug|x64
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Release|Win32.Build.0 = Release|Win32
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Release|x64.ActiveCfg = Release|x64
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554}.Release|x64.Build.0 = Release|x64
|
||||
CONF_ENTRIES
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,19 +0,0 @@
|
||||
# Python package requirements for driver implementers.
|
||||
|
||||
# Jinja2 <3.0 needs an older version of markupsafe, but does not
|
||||
# declare it.
|
||||
# https://github.com/pallets/markupsafe/issues/282
|
||||
# https://github.com/pallets/jinja/issues/1585
|
||||
markupsafe < 2.1
|
||||
|
||||
# Use the version of Jinja that's in Ubuntu 20.04.
|
||||
# See https://github.com/Mbed-TLS/mbedtls/pull/5067#discussion_r738794607 .
|
||||
# Note that Jinja 3.0 drops support for Python 3.5, so we need to support
|
||||
# Jinja 2.x as long as we're still using Python 3.5 anywhere.
|
||||
# Jinja 2.10.1 doesn't support Python 3.10+
|
||||
Jinja2 >= 2.10.1; python_version < '3.10'
|
||||
Jinja2 >= 2.10.3; python_version >= '3.10'
|
||||
# Jinja2 >=2.10, <3.0 needs a separate package for type annotations
|
||||
types-Jinja2 >= 2.11.9
|
||||
jsonschema >= 3.2.0
|
||||
types-jsonschema >= 3.2.0
|
||||
@@ -1,87 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Measure heap usage (and performance) of ECC operations with various values of
|
||||
# the relevant tunable compile-time parameters.
|
||||
#
|
||||
# Usage (preferably on a 32-bit platform):
|
||||
# cmake -D CMAKE_BUILD_TYPE=Release .
|
||||
# scripts/ecc-heap.sh | tee ecc-heap.log
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
set -eu
|
||||
|
||||
CONFIG_H='include/mbedtls/mbedtls_config.h'
|
||||
|
||||
if [ -r $CONFIG_H ]; then :; else
|
||||
echo "$CONFIG_H not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -i cmake Makefile >/dev/null; then :; else
|
||||
echo "Needs Cmake" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git status | grep -F $CONFIG_H >/dev/null 2>&1; then
|
||||
echo "mbedtls_config.h not clean" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONFIG_BAK=${CONFIG_H}.bak
|
||||
cp $CONFIG_H $CONFIG_BAK
|
||||
|
||||
cat << EOF >$CONFIG_H
|
||||
#define MBEDTLS_PLATFORM_C
|
||||
#define MBEDTLS_PLATFORM_MEMORY
|
||||
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
|
||||
#define MBEDTLS_MEMORY_DEBUG
|
||||
|
||||
#define MBEDTLS_TIMING_C
|
||||
|
||||
#define MBEDTLS_BIGNUM_C
|
||||
#define MBEDTLS_ECP_C
|
||||
#define MBEDTLS_ASN1_PARSE_C
|
||||
#define MBEDTLS_ASN1_WRITE_C
|
||||
#define MBEDTLS_ECDSA_C
|
||||
#define MBEDTLS_SHA256_C // ECDSA benchmark needs it
|
||||
#define MBEDTLS_SHA224_C // SHA256 requires this for now
|
||||
#define MBEDTLS_ECDH_C
|
||||
|
||||
// NIST curves >= 256 bits
|
||||
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
|
||||
#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
|
||||
// SECP "koblitz-like" curve >= 256 bits
|
||||
#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
|
||||
// Brainpool curves (no specialised "mod p" routine)
|
||||
#define MBEDTLS_ECP_DP_BP256R1_ENABLED
|
||||
#define MBEDTLS_ECP_DP_BP384R1_ENABLED
|
||||
#define MBEDTLS_ECP_DP_BP512R1_ENABLED
|
||||
// Montgomery curves
|
||||
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
|
||||
#define MBEDTLS_ECP_DP_CURVE448_ENABLED
|
||||
|
||||
#define MBEDTLS_HAVE_ASM // just make things a bit faster
|
||||
#define MBEDTLS_ECP_NIST_OPTIM // faster and less allocations
|
||||
|
||||
//#define MBEDTLS_ECP_WINDOW_SIZE 4
|
||||
//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1
|
||||
EOF
|
||||
|
||||
for F in 0 1; do
|
||||
for W in 2 3 4; do
|
||||
scripts/config.py set MBEDTLS_ECP_WINDOW_SIZE $W
|
||||
scripts/config.py set MBEDTLS_ECP_FIXED_POINT_OPTIM $F
|
||||
make benchmark >/dev/null 2>&1
|
||||
echo "fixed point optim = $F, max window size = $W"
|
||||
echo "--------------------------------------------"
|
||||
programs/test/benchmark ecdh ecdsa
|
||||
done
|
||||
done
|
||||
|
||||
# cleanup
|
||||
|
||||
mv $CONFIG_BAK $CONFIG_H
|
||||
make clean
|
||||
@@ -1,237 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Purpose
|
||||
|
||||
This script dumps comb table of ec curve. When you add a new ec curve, you
|
||||
can use this script to generate codes to define `<curve>_T` in ecp_curves.c
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
HOW_TO_ADD_NEW_CURVE = """
|
||||
If you are trying to add new curve, you can follow these steps:
|
||||
|
||||
1. Define curve parameters (<curve>_p, <curve>_gx, etc...) in ecp_curves.c.
|
||||
2. Add a macro to define <curve>_T to NULL following these parameters.
|
||||
3. Build mbedcrypto
|
||||
4. Run this script with an argument of new curve
|
||||
5. Copy the output of this script into ecp_curves.c and replace the macro added
|
||||
in Step 2
|
||||
6. Rebuild and test if everything is ok
|
||||
|
||||
Replace the <curve> in the above with the name of the curve you want to add."""
|
||||
|
||||
CC = os.getenv('CC', 'cc')
|
||||
MBEDTLS_LIBRARY_PATH = os.getenv('MBEDTLS_LIBRARY_PATH', "library")
|
||||
|
||||
SRC_DUMP_COMB_TABLE = r'''
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/error.h"
|
||||
|
||||
static void dump_mpi_initialize( const char *name, const mbedtls_mpi *d )
|
||||
{
|
||||
uint8_t buf[128] = {0};
|
||||
size_t olen;
|
||||
uint8_t *p;
|
||||
|
||||
olen = mbedtls_mpi_size( d );
|
||||
mbedtls_mpi_write_binary_le( d, buf, olen );
|
||||
printf("static const mbedtls_mpi_uint %s[] = {\n", name);
|
||||
for (p = buf; p < buf + olen; p += 8) {
|
||||
printf( " BYTES_TO_T_UINT_8( 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X ),\n",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] );
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
static void dump_T( const mbedtls_ecp_group *grp )
|
||||
{
|
||||
char name[128];
|
||||
|
||||
printf( "#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1\n" );
|
||||
|
||||
for (size_t i = 0; i < grp->T_size; ++i) {
|
||||
snprintf( name, sizeof(name), "%s_T_%zu_X", CURVE_NAME, i );
|
||||
dump_mpi_initialize( name, &grp->T[i].X );
|
||||
|
||||
snprintf( name, sizeof(name), "%s_T_%zu_Y", CURVE_NAME, i );
|
||||
dump_mpi_initialize( name, &grp->T[i].Y );
|
||||
}
|
||||
printf( "static const mbedtls_ecp_point %s_T[%zu] = {\n", CURVE_NAME, grp->T_size );
|
||||
size_t olen;
|
||||
for (size_t i = 0; i < grp->T_size; ++i) {
|
||||
int z;
|
||||
if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 0) == 0 ) {
|
||||
z = 0;
|
||||
} else if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 1) == 0 ) {
|
||||
z = 1;
|
||||
} else {
|
||||
fprintf( stderr, "Unexpected value of Z (i = %d)\n", (int)i );
|
||||
exit( 1 );
|
||||
}
|
||||
printf( " ECP_POINT_INIT_XY_Z%d(%s_T_%zu_X, %s_T_%zu_Y),\n",
|
||||
z,
|
||||
CURVE_NAME, i,
|
||||
CURVE_NAME, i
|
||||
);
|
||||
}
|
||||
printf("};\n#endif\n\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int rc;
|
||||
mbedtls_mpi m;
|
||||
mbedtls_ecp_point R;
|
||||
mbedtls_ecp_group grp;
|
||||
|
||||
mbedtls_ecp_group_init( &grp );
|
||||
rc = mbedtls_ecp_group_load( &grp, CURVE_ID );
|
||||
if (rc != 0) {
|
||||
char buf[100];
|
||||
mbedtls_strerror( rc, buf, sizeof(buf) );
|
||||
fprintf( stderr, "mbedtls_ecp_group_load: %s (-0x%x)\n", buf, -rc );
|
||||
return 1;
|
||||
}
|
||||
grp.T = NULL;
|
||||
mbedtls_ecp_point_init( &R );
|
||||
mbedtls_mpi_init( &m);
|
||||
mbedtls_mpi_lset( &m, 1 );
|
||||
rc = mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL );
|
||||
if ( rc != 0 ) {
|
||||
char buf[100];
|
||||
mbedtls_strerror( rc, buf, sizeof(buf) );
|
||||
fprintf( stderr, "mbedtls_ecp_mul: %s (-0x%x)\n", buf, -rc );
|
||||
return 1;
|
||||
}
|
||||
if ( grp.T == NULL ) {
|
||||
fprintf( stderr, "grp.T is not generated. Please make sure"
|
||||
"MBEDTLS_ECP_FIXED_POINT_OPTIM is enabled in mbedtls_config.h\n" );
|
||||
return 1;
|
||||
}
|
||||
dump_T( &grp );
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
|
||||
SRC_DUMP_KNOWN_CURVE = r'''
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mbedtls/ecp.h"
|
||||
|
||||
int main() {
|
||||
const mbedtls_ecp_curve_info *info = mbedtls_ecp_curve_list();
|
||||
mbedtls_ecp_group grp;
|
||||
|
||||
mbedtls_ecp_group_init( &grp );
|
||||
while ( info->name != NULL ) {
|
||||
mbedtls_ecp_group_load( &grp, info->grp_id );
|
||||
if ( mbedtls_ecp_get_type(&grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) {
|
||||
printf( " %s", info->name );
|
||||
}
|
||||
info++;
|
||||
}
|
||||
printf( "\n" );
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
def join_src_path(*args):
|
||||
return os.path.normpath(os.path.join(os.path.dirname(__file__), "..", *args))
|
||||
|
||||
|
||||
def run_c_source(src, cflags):
|
||||
"""
|
||||
Compile and run C source code
|
||||
:param src: the c language code to run
|
||||
:param cflags: additional cflags passing to compiler
|
||||
:return:
|
||||
"""
|
||||
binname = tempfile.mktemp(prefix="mbedtls")
|
||||
fd, srcname = tempfile.mkstemp(prefix="mbedtls", suffix=".c")
|
||||
srcfile = os.fdopen(fd, mode="w")
|
||||
srcfile.write(src)
|
||||
srcfile.close()
|
||||
args = [CC,
|
||||
*cflags,
|
||||
'-I' + join_src_path("include"),
|
||||
"-o", binname,
|
||||
'-L' + MBEDTLS_LIBRARY_PATH,
|
||||
srcname,
|
||||
'-lmbedcrypto']
|
||||
|
||||
p = subprocess.run(args=args, check=False)
|
||||
if p.returncode != 0:
|
||||
return False
|
||||
p = subprocess.run(args=[binname], check=False, env={
|
||||
'LD_LIBRARY_PATH': MBEDTLS_LIBRARY_PATH
|
||||
})
|
||||
if p.returncode != 0:
|
||||
return False
|
||||
os.unlink(srcname)
|
||||
os.unlink(binname)
|
||||
return True
|
||||
|
||||
|
||||
def compute_curve(curve):
|
||||
"""compute comb table for curve"""
|
||||
r = run_c_source(
|
||||
SRC_DUMP_COMB_TABLE,
|
||||
[
|
||||
'-g',
|
||||
'-DCURVE_ID=MBEDTLS_ECP_DP_%s' % curve.upper(),
|
||||
'-DCURVE_NAME="%s"' % curve.lower(),
|
||||
])
|
||||
if not r:
|
||||
print("""\
|
||||
Unable to compile and run utility.""", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def usage():
|
||||
print("""
|
||||
Usage: python %s <curve>...
|
||||
|
||||
Arguments:
|
||||
curve Specify one or more curve names (e.g secp256r1)
|
||||
|
||||
All possible curves: """ % sys.argv[0])
|
||||
run_c_source(SRC_DUMP_KNOWN_CURVE, [])
|
||||
print("""
|
||||
Environment Variable:
|
||||
CC Specify which c compile to use to compile utility.
|
||||
MBEDTLS_LIBRARY_PATH
|
||||
Specify the path to mbedcrypto library. (e.g. build/library/)
|
||||
|
||||
How to add a new curve: %s""" % HOW_TO_ADD_NEW_CURVE)
|
||||
|
||||
|
||||
def run_main():
|
||||
shared_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.so"))
|
||||
static_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.a"))
|
||||
if not os.path.exists(shared_lib_path) and not os.path.exists(static_lib_path):
|
||||
print("Warning: both '%s' and '%s' are not exists. This script will use "
|
||||
"the library from your system instead of the library compiled by "
|
||||
"this source directory.\n"
|
||||
"You can specify library path using environment variable "
|
||||
"'MBEDTLS_LIBRARY_PATH'." % (shared_lib_path, static_lib_path),
|
||||
file=sys.stderr)
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
usage()
|
||||
else:
|
||||
for curve in sys.argv[1:]:
|
||||
compute_curve(curve)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_main()
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
#
|
||||
# Purpose
|
||||
#
|
||||
# This script determines ROM size (or code size) for the standard Mbed TLS
|
||||
# configurations, when built for a Cortex M3/M4 target.
|
||||
#
|
||||
# Configurations included:
|
||||
# default include/mbedtls/mbedtls_config.h
|
||||
# thread configs/config-thread.h
|
||||
# suite-b configs/config-suite-b.h
|
||||
# psk configs/config-ccm-psk-tls1_2.h
|
||||
#
|
||||
# Usage: footprint.sh
|
||||
#
|
||||
set -eu
|
||||
|
||||
CONFIG_H='include/mbedtls/mbedtls_config.h'
|
||||
|
||||
if [ -r $CONFIG_H ]; then :; else
|
||||
echo "$CONFIG_H not found" >&2
|
||||
echo "This script needs to be run from the root of" >&2
|
||||
echo "a git checkout or uncompressed tarball" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -i cmake Makefile >/dev/null; then
|
||||
echo "Not compatible with CMake" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if which arm-none-eabi-gcc >/dev/null 2>&1; then :; else
|
||||
echo "You need the ARM-GCC toolchain in your path" >&2
|
||||
echo "See https://launchpad.net/gcc-arm-embedded/" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARMGCC_FLAGS='-Os -march=armv7-m -mthumb'
|
||||
OUTFILE='00-footprint-summary.txt'
|
||||
|
||||
log()
|
||||
{
|
||||
echo "$@"
|
||||
echo "$@" >> "$OUTFILE"
|
||||
}
|
||||
|
||||
doit()
|
||||
{
|
||||
NAME="$1"
|
||||
FILE="$2"
|
||||
|
||||
log ""
|
||||
log "$NAME ($FILE):"
|
||||
|
||||
cp $CONFIG_H ${CONFIG_H}.bak
|
||||
if [ "$FILE" != $CONFIG_H ]; then
|
||||
cp "$FILE" $CONFIG_H
|
||||
fi
|
||||
|
||||
{
|
||||
scripts/config.py unset MBEDTLS_NET_C || true
|
||||
scripts/config.py unset MBEDTLS_TIMING_C || true
|
||||
scripts/config.py unset MBEDTLS_FS_IO || true
|
||||
scripts/config.py --force set MBEDTLS_NO_PLATFORM_ENTROPY || true
|
||||
} >/dev/null 2>&1
|
||||
|
||||
make clean >/dev/null
|
||||
CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld \
|
||||
CFLAGS="$ARMGCC_FLAGS" make lib >/dev/null
|
||||
|
||||
OUT="size-${NAME}.txt"
|
||||
arm-none-eabi-size -t library/libmbed*.a > "$OUT"
|
||||
log "$( head -n1 "$OUT" )"
|
||||
log "$( tail -n1 "$OUT" )"
|
||||
|
||||
cp ${CONFIG_H}.bak $CONFIG_H
|
||||
}
|
||||
|
||||
# truncate the file just this time
|
||||
echo "(generated by $0)" > "$OUTFILE"
|
||||
echo "" >> "$OUTFILE"
|
||||
|
||||
log "Footprint of standard configurations (minus net_sockets.c, timing.c, fs_io)"
|
||||
log "for bare-metal ARM Cortex-M3/M4 microcontrollers."
|
||||
|
||||
VERSION_H="include/mbedtls/version.h"
|
||||
MBEDTLS_VERSION=$( sed -n 's/.*VERSION_STRING *"\(.*\)"/\1/p' $VERSION_H )
|
||||
if git rev-parse HEAD >/dev/null; then
|
||||
GIT_HEAD=$( git rev-parse HEAD | head -c 10 )
|
||||
GIT_VERSION=" (git head: $GIT_HEAD)"
|
||||
else
|
||||
GIT_VERSION=""
|
||||
fi
|
||||
|
||||
log ""
|
||||
log "Mbed TLS $MBEDTLS_VERSION$GIT_VERSION"
|
||||
log "$( arm-none-eabi-gcc --version | head -n1 )"
|
||||
log "CFLAGS=$ARMGCC_FLAGS"
|
||||
|
||||
doit default include/mbedtls/mbedtls_config.h
|
||||
doit thread configs/config-thread.h
|
||||
doit suite-b configs/config-suite-b.h
|
||||
doit psk configs/config-ccm-psk-tls1_2.h
|
||||
|
||||
zip mbedtls-footprint.zip "$OUTFILE" size-*.txt >/dev/null
|
||||
@@ -1,17 +0,0 @@
|
||||
"""Add our Python library directory to the module search path.
|
||||
|
||||
Usage:
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),
|
||||
os.path.pardir,
|
||||
'framework', 'scripts'))
|
||||
@@ -1,214 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate psa_crypto_driver_wrappers.h
|
||||
psa_crypto_driver_wrappers_no_static.c
|
||||
|
||||
This module is invoked by the build scripts to auto generate the
|
||||
psa_crypto_driver_wrappers.h and psa_crypto_driver_wrappers_no_static
|
||||
based on template files in script/data_files/driver_templates/.
|
||||
"""
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
from typing import NewType, Dict, Any
|
||||
from traceback import format_tb
|
||||
import argparse
|
||||
import jsonschema
|
||||
import jinja2
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import build_tree
|
||||
|
||||
JSONSchema = NewType('JSONSchema', object)
|
||||
# The Driver is an Object, but practically it's indexable and can called a dictionary to
|
||||
# keep MyPy happy till MyPy comes with a more composite type for JsonObjects.
|
||||
Driver = NewType('Driver', dict)
|
||||
|
||||
|
||||
class JsonValidationException(Exception):
|
||||
def __init__(self, message="Json Validation Failed"):
|
||||
self.message = message
|
||||
super().__init__(self.message)
|
||||
|
||||
|
||||
class DriverReaderException(Exception):
|
||||
def __init__(self, message="Driver Reader Failed"):
|
||||
self.message = message
|
||||
super().__init__(self.message)
|
||||
|
||||
|
||||
def render(template_path: str, driver_jsoncontext: list) -> str:
|
||||
"""
|
||||
Render template from the input file and driver JSON.
|
||||
"""
|
||||
environment = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader(os.path.dirname(template_path)),
|
||||
keep_trailing_newline=True)
|
||||
template = environment.get_template(os.path.basename(template_path))
|
||||
|
||||
return template.render(drivers=driver_jsoncontext)
|
||||
|
||||
def generate_driver_wrapper_file(template_dir: str,
|
||||
output_dir: str,
|
||||
template_file_name: str,
|
||||
driver_jsoncontext: list) -> None:
|
||||
"""
|
||||
Generate the file psa_crypto_driver_wrapper.c.
|
||||
"""
|
||||
driver_wrapper_template_filename = \
|
||||
os.path.join(template_dir, template_file_name)
|
||||
|
||||
result = render(driver_wrapper_template_filename, driver_jsoncontext)
|
||||
|
||||
with open(file=os.path.join(output_dir, os.path.splitext(template_file_name)[0]),
|
||||
mode='w',
|
||||
encoding='UTF-8') as out_file:
|
||||
out_file.write(result)
|
||||
|
||||
|
||||
def validate_json(driverjson_data: Driver, driverschema_list: dict) -> None:
|
||||
"""
|
||||
Validate the Driver JSON against an appropriate schema
|
||||
the schema passed could be that matching an opaque/ transparent driver.
|
||||
"""
|
||||
driver_type = driverjson_data["type"]
|
||||
driver_prefix = driverjson_data["prefix"]
|
||||
try:
|
||||
_schema = driverschema_list[driver_type]
|
||||
jsonschema.validate(instance=driverjson_data, schema=_schema)
|
||||
except KeyError as err:
|
||||
# This could happen if the driverjson_data.type does not exist in the provided schema list
|
||||
# schemas = {'transparent': transparent_driver_schema, 'opaque': opaque_driver_schema}
|
||||
# Print onto stdout and stderr.
|
||||
print("Unknown Driver type " + driver_type +
|
||||
" for driver " + driver_prefix, str(err))
|
||||
print("Unknown Driver type " + driver_type +
|
||||
" for driver " + driver_prefix, str(err), file=sys.stderr)
|
||||
raise JsonValidationException() from err
|
||||
|
||||
except jsonschema.exceptions.ValidationError as err:
|
||||
# Print onto stdout and stderr.
|
||||
print("Error: Failed to validate data file: {} using schema: {}."
|
||||
"\n Exception Message: \"{}\""
|
||||
" ".format(driverjson_data, _schema, str(err)))
|
||||
print("Error: Failed to validate data file: {} using schema: {}."
|
||||
"\n Exception Message: \"{}\""
|
||||
" ".format(driverjson_data, _schema, str(err)), file=sys.stderr)
|
||||
raise JsonValidationException() from err
|
||||
|
||||
|
||||
def load_driver(schemas: Dict[str, Any], driver_file: str) -> Any:
|
||||
"""loads validated json driver"""
|
||||
with open(file=driver_file, mode='r', encoding='UTF-8') as f:
|
||||
json_data = json.load(f)
|
||||
try:
|
||||
validate_json(json_data, schemas)
|
||||
except JsonValidationException as e:
|
||||
raise DriverReaderException from e
|
||||
return json_data
|
||||
|
||||
|
||||
def load_schemas(project_root: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Load schemas map
|
||||
"""
|
||||
schema_file_paths = {
|
||||
'transparent': os.path.join(project_root,
|
||||
'scripts',
|
||||
'data_files',
|
||||
'driver_jsons',
|
||||
'driver_transparent_schema.json'),
|
||||
'opaque': os.path.join(project_root,
|
||||
'scripts',
|
||||
'data_files',
|
||||
'driver_jsons',
|
||||
'driver_opaque_schema.json')
|
||||
}
|
||||
driver_schema = {}
|
||||
for key, file_path in schema_file_paths.items():
|
||||
with open(file=file_path, mode='r', encoding='UTF-8') as file:
|
||||
driver_schema[key] = json.load(file)
|
||||
return driver_schema
|
||||
|
||||
|
||||
def read_driver_descriptions(project_root: str,
|
||||
json_directory: str,
|
||||
jsondriver_list: str) -> list:
|
||||
"""
|
||||
Merge driver JSON files into a single ordered JSON after validation.
|
||||
"""
|
||||
driver_schema = load_schemas(project_root)
|
||||
|
||||
with open(file=os.path.join(json_directory, jsondriver_list),
|
||||
mode='r',
|
||||
encoding='UTF-8') as driver_list_file:
|
||||
driver_list = json.load(driver_list_file)
|
||||
|
||||
return [load_driver(schemas=driver_schema,
|
||||
driver_file=os.path.join(json_directory, driver_file_name))
|
||||
for driver_file_name in driver_list]
|
||||
|
||||
|
||||
def trace_exception(e: Exception, file=sys.stderr) -> None:
|
||||
"""Prints exception trace to the given TextIO handle"""
|
||||
print("Exception: type: %s, message: %s, trace: %s" % (
|
||||
e.__class__, str(e), format_tb(e.__traceback__)
|
||||
), file)
|
||||
|
||||
|
||||
TEMPLATE_FILENAMES = ["psa_crypto_driver_wrappers.h.jinja",
|
||||
"psa_crypto_driver_wrappers_no_static.c.jinja"]
|
||||
|
||||
def main() -> int:
|
||||
"""
|
||||
Main with command line arguments.
|
||||
"""
|
||||
def_arg_project_root = build_tree.guess_project_root()
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--project-root', default=def_arg_project_root,
|
||||
help='root directory of repo source code')
|
||||
parser.add_argument('--template-dir',
|
||||
help='directory holding the driver templates')
|
||||
parser.add_argument('--json-dir',
|
||||
help='directory holding the driver JSONs')
|
||||
parser.add_argument('output_directory', nargs='?',
|
||||
help='output file\'s location')
|
||||
args = parser.parse_args()
|
||||
|
||||
project_root = os.path.abspath(args.project_root)
|
||||
|
||||
crypto_core_directory = build_tree.crypto_core_directory(project_root)
|
||||
|
||||
output_directory = args.output_directory if args.output_directory is not None else \
|
||||
crypto_core_directory
|
||||
|
||||
template_directory = args.template_dir if args.template_dir is not None else \
|
||||
os.path.join(project_root,
|
||||
'scripts',
|
||||
'data_files',
|
||||
'driver_templates')
|
||||
json_directory = args.json_dir if args.json_dir is not None else \
|
||||
os.path.join(project_root,
|
||||
'scripts',
|
||||
'data_files',
|
||||
'driver_jsons')
|
||||
|
||||
try:
|
||||
# Read and validate list of driver jsons from driverlist.json
|
||||
merged_driver_json = read_driver_descriptions(project_root,
|
||||
json_directory,
|
||||
'driverlist.json')
|
||||
except DriverReaderException as e:
|
||||
trace_exception(e)
|
||||
return 1
|
||||
for template_filename in TEMPLATE_FILENAMES:
|
||||
generate_driver_wrapper_file(template_directory, output_directory,
|
||||
template_filename, merged_driver_json)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,243 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Generate error.c
|
||||
#
|
||||
# Usage: ./generate_errors.pl or scripts/generate_errors.pl without arguments,
|
||||
# or generate_errors.pl crypto_include_dir tls_include_dir data_dir error_file
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my ($crypto_include_dir, $tls_include_dir, $data_dir, $error_file);
|
||||
|
||||
if( @ARGV ) {
|
||||
die "Invalid number of arguments" if scalar @ARGV != 4;
|
||||
($crypto_include_dir, $tls_include_dir, $data_dir, $error_file) = @ARGV;
|
||||
|
||||
-d $crypto_include_dir or die "No such directory: $crypto_include_dir\n";
|
||||
-d $tls_include_dir or die "No such directory: $tls_include_dir\n";
|
||||
-d $data_dir or die "No such directory: $data_dir\n";
|
||||
} else {
|
||||
$crypto_include_dir = 'tf-psa-crypto/drivers/builtin/include/mbedtls';
|
||||
$tls_include_dir = 'include/mbedtls';
|
||||
$data_dir = 'scripts/data_files';
|
||||
$error_file = 'tf-psa-crypto/drivers/builtin/src/error.c';
|
||||
|
||||
unless( -d $crypto_include_dir && -d $tls_include_dir && -d $data_dir ) {
|
||||
chdir '..' or die;
|
||||
-d $crypto_include_dir && -d $tls_include_dir && -d $data_dir
|
||||
or die "Without arguments, must be run from root or scripts\n"
|
||||
}
|
||||
}
|
||||
|
||||
my $error_format_file = $data_dir.'/error.fmt';
|
||||
|
||||
my @low_level_modules = qw( AES ARIA ASN1 BASE64 BIGNUM
|
||||
CAMELLIA CCM CHACHA20 CHACHAPOLY CMAC CTR_DRBG DES
|
||||
ENTROPY ERROR GCM HKDF HMAC_DRBG LMS MD5
|
||||
NET OID PBKDF2 PLATFORM POLY1305 RIPEMD160
|
||||
SHA1 SHA256 SHA512 SHA3 THREADING );
|
||||
my @high_level_modules = qw( CIPHER DHM ECP MD
|
||||
PEM PK PKCS12 PKCS5
|
||||
RSA SSL X509 PKCS7 );
|
||||
|
||||
undef $/;
|
||||
|
||||
open(FORMAT_FILE, '<:crlf', "$error_format_file") or die "Opening error format file '$error_format_file': $!";
|
||||
my $error_format = <FORMAT_FILE>;
|
||||
close(FORMAT_FILE);
|
||||
|
||||
my @files = glob qq("$crypto_include_dir/*.h");
|
||||
push(@files, glob qq("$tls_include_dir/*.h"));
|
||||
my @necessary_include_files;
|
||||
my @matches;
|
||||
foreach my $file (@files) {
|
||||
open(FILE, '<:crlf', $file) or die("$0: $file: $!");
|
||||
my $content = <FILE>;
|
||||
close FILE;
|
||||
my $found = 0;
|
||||
while ($content =~ m[
|
||||
# Both the before-comment and the after-comment are optional.
|
||||
# Only the comment content is a regex capture group. The comment
|
||||
# start and end parts are outside the capture group.
|
||||
(?:/\*[*!](?!<) # Doxygen before-comment start
|
||||
((?:[^*]|\*+[^*/])*) # $1: Comment content (no */ inside)
|
||||
\*/)? # Comment end
|
||||
\s*\#\s*define\s+(MBEDTLS_ERR_\w+) # $2: name
|
||||
\s+\-(0[Xx][0-9A-Fa-f]+)\s* # $3: value (without the sign)
|
||||
(?:/\*[*!]< # Doxygen after-comment start
|
||||
((?:[^*]|\*+[^*/])*) # $4: Comment content (no */ inside)
|
||||
\*/)? # Comment end
|
||||
]gsx) {
|
||||
my ($before, $name, $value, $after) = ($1, $2, $3, $4);
|
||||
# Discard Doxygen comments that are coincidentally present before
|
||||
# an error definition but not attached to it. This is ad hoc, based
|
||||
# on what actually matters (or mattered at some point).
|
||||
undef $before if defined($before) && $before =~ /\s*\\name\s/s;
|
||||
die "Description neither before nor after $name in $file\n"
|
||||
if !defined($before) && !defined($after);
|
||||
die "Description both before and after $name in $file\n"
|
||||
if defined($before) && defined($after);
|
||||
my $description = (defined($before) ? $before : $after);
|
||||
$description =~ s/^\s+//;
|
||||
$description =~ s/\n( *\*)? */ /g;
|
||||
$description =~ s/\.?\s+$//;
|
||||
push @matches, [$name, $value, $description];
|
||||
++$found;
|
||||
}
|
||||
if ($found) {
|
||||
my $include_name = $file;
|
||||
$include_name =~ s!.*/!!;
|
||||
push @necessary_include_files, $include_name;
|
||||
}
|
||||
}
|
||||
|
||||
my $ll_old_define = "";
|
||||
my $hl_old_define = "";
|
||||
|
||||
my $ll_code_check = "";
|
||||
my $hl_code_check = "";
|
||||
|
||||
my $headers = "";
|
||||
my %included_headers;
|
||||
|
||||
my %error_codes_seen;
|
||||
|
||||
foreach my $match (@matches)
|
||||
{
|
||||
my ($error_name, $error_code, $description) = @$match;
|
||||
|
||||
die "Duplicated error code: $error_code ($error_name)\n"
|
||||
if( $error_codes_seen{$error_code}++ );
|
||||
|
||||
$description =~ s/\\/\\\\/g;
|
||||
|
||||
my ($module_name) = $error_name =~ /^MBEDTLS_ERR_([^_]+)/;
|
||||
|
||||
# Fix faulty ones
|
||||
$module_name = "BIGNUM" if ($module_name eq "MPI");
|
||||
$module_name = "CTR_DRBG" if ($module_name eq "CTR");
|
||||
$module_name = "HMAC_DRBG" if ($module_name eq "HMAC");
|
||||
|
||||
my $define_name = $module_name;
|
||||
$define_name = "X509_USE,X509_CREATE" if ($define_name eq "X509");
|
||||
$define_name = "ASN1_PARSE" if ($define_name eq "ASN1");
|
||||
$define_name = "SSL_TLS" if ($define_name eq "SSL");
|
||||
$define_name = "PEM_PARSE,PEM_WRITE" if ($define_name eq "PEM");
|
||||
$define_name = "PKCS7" if ($define_name eq "PKCS7");
|
||||
|
||||
my $include_name = $module_name;
|
||||
$include_name =~ tr/A-Z/a-z/;
|
||||
|
||||
# Fix faulty ones
|
||||
$include_name = "net_sockets" if ($module_name eq "NET");
|
||||
|
||||
$included_headers{"${include_name}.h"} = $module_name;
|
||||
|
||||
my $found_ll = grep $_ eq $module_name, @low_level_modules;
|
||||
my $found_hl = grep $_ eq $module_name, @high_level_modules;
|
||||
if (!$found_ll && !$found_hl)
|
||||
{
|
||||
printf("Error: Do not know how to handle: $module_name\n");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $code_check;
|
||||
my $old_define;
|
||||
my $white_space;
|
||||
my $first;
|
||||
|
||||
if ($found_ll)
|
||||
{
|
||||
$code_check = \$ll_code_check;
|
||||
$old_define = \$ll_old_define;
|
||||
$white_space = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$code_check = \$hl_code_check;
|
||||
$old_define = \$hl_old_define;
|
||||
$white_space = ' ';
|
||||
}
|
||||
|
||||
if ($define_name ne ${$old_define})
|
||||
{
|
||||
if (${$old_define} ne "")
|
||||
{
|
||||
${$code_check} .= "#endif /* ";
|
||||
$first = 0;
|
||||
foreach my $dep (split(/,/, ${$old_define}))
|
||||
{
|
||||
${$code_check} .= " || " if ($first++);
|
||||
${$code_check} .= "MBEDTLS_${dep}_C";
|
||||
}
|
||||
${$code_check} .= " */\n\n";
|
||||
}
|
||||
|
||||
${$code_check} .= "#if ";
|
||||
$headers .= "#if " if ($include_name ne "");
|
||||
$first = 0;
|
||||
foreach my $dep (split(/,/, ${define_name}))
|
||||
{
|
||||
${$code_check} .= " || " if ($first);
|
||||
$headers .= " || " if ($first++);
|
||||
|
||||
${$code_check} .= "defined(MBEDTLS_${dep}_C)";
|
||||
$headers .= "defined(MBEDTLS_${dep}_C)" if
|
||||
($include_name ne "");
|
||||
}
|
||||
${$code_check} .= "\n";
|
||||
$headers .= "\n#include \"mbedtls/${include_name}.h\"\n".
|
||||
"#endif\n\n" if ($include_name ne "");
|
||||
${$old_define} = $define_name;
|
||||
}
|
||||
|
||||
${$code_check} .= "${white_space}case -($error_name):\n".
|
||||
"${white_space} return( \"$module_name - $description\" );\n"
|
||||
};
|
||||
|
||||
if ($ll_old_define ne "")
|
||||
{
|
||||
$ll_code_check .= "#endif /* ";
|
||||
my $first = 0;
|
||||
foreach my $dep (split(/,/, $ll_old_define))
|
||||
{
|
||||
$ll_code_check .= " || " if ($first++);
|
||||
$ll_code_check .= "MBEDTLS_${dep}_C";
|
||||
}
|
||||
$ll_code_check .= " */\n";
|
||||
}
|
||||
if ($hl_old_define ne "")
|
||||
{
|
||||
$hl_code_check .= "#endif /* ";
|
||||
my $first = 0;
|
||||
foreach my $dep (split(/,/, $hl_old_define))
|
||||
{
|
||||
$hl_code_check .= " || " if ($first++);
|
||||
$hl_code_check .= "MBEDTLS_${dep}_C";
|
||||
}
|
||||
$hl_code_check .= " */\n";
|
||||
}
|
||||
|
||||
$error_format =~ s/HEADER_INCLUDED\n/$headers/g;
|
||||
$error_format =~ s/LOW_LEVEL_CODE_CHECKS\n/$ll_code_check/g;
|
||||
$error_format =~ s/HIGH_LEVEL_CODE_CHECKS\n/$hl_code_check/g;
|
||||
|
||||
open(ERROR_FILE, ">$error_file") or die "Opening destination file '$error_file': $!";
|
||||
print ERROR_FILE $error_format;
|
||||
close(ERROR_FILE);
|
||||
|
||||
my $errors = 0;
|
||||
for my $include_name (@necessary_include_files)
|
||||
{
|
||||
if (not $included_headers{$include_name})
|
||||
{
|
||||
print STDERR "The header file \"$include_name\" defines error codes but has not been included!\n";
|
||||
++$errors;
|
||||
}
|
||||
}
|
||||
|
||||
exit !!$errors;
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
use strict;
|
||||
|
||||
my ($include_dir, $data_dir, $feature_file);
|
||||
|
||||
if( @ARGV ) {
|
||||
die "Invalid number of arguments" if scalar @ARGV != 3;
|
||||
($include_dir, $data_dir, $feature_file) = @ARGV;
|
||||
|
||||
-d $include_dir or die "No such directory: $include_dir\n";
|
||||
-d $data_dir or die "No such directory: $data_dir\n";
|
||||
} else {
|
||||
$include_dir = 'include/mbedtls';
|
||||
$data_dir = 'scripts/data_files';
|
||||
$feature_file = 'tf-psa-crypto/drivers/builtin/src/version_features.c';
|
||||
|
||||
unless( -d $include_dir && -d $data_dir ) {
|
||||
chdir '..' or die;
|
||||
-d $include_dir && -d $data_dir
|
||||
or die "Without arguments, must be run from root or scripts\n"
|
||||
}
|
||||
}
|
||||
|
||||
my $feature_format_file = $data_dir.'/version_features.fmt';
|
||||
|
||||
my @sections = ( "System support", "Mbed TLS modules",
|
||||
"Mbed TLS feature support" );
|
||||
|
||||
my $line_separator = $/;
|
||||
undef $/;
|
||||
|
||||
open(FORMAT_FILE, '<:crlf', "$feature_format_file") or die "Opening feature format file '$feature_format_file': $!";
|
||||
my $feature_format = <FORMAT_FILE>;
|
||||
close(FORMAT_FILE);
|
||||
|
||||
$/ = $line_separator;
|
||||
|
||||
open(CONFIG_H, '<:crlf', "$include_dir/mbedtls_config.h") || die("Failure when opening mbedtls_config.h: $!");
|
||||
|
||||
my $feature_defines = "";
|
||||
my $in_section = 0;
|
||||
|
||||
while (my $line = <CONFIG_H>)
|
||||
{
|
||||
next if ($in_section && $line !~ /#define/ && $line !~ /SECTION/);
|
||||
next if (!$in_section && $line !~ /SECTION/);
|
||||
|
||||
if ($in_section) {
|
||||
if ($line =~ /SECTION/) {
|
||||
$in_section = 0;
|
||||
next;
|
||||
}
|
||||
# Strip leading MBEDTLS_ to save binary size
|
||||
my ($mbedtls_prefix, $define) = $line =~ /#define (MBEDTLS_)?(\w+)/;
|
||||
if (!$mbedtls_prefix) {
|
||||
die "Feature does not start with 'MBEDTLS_': $line\n";
|
||||
}
|
||||
$feature_defines .= "#if defined(MBEDTLS_${define})\n";
|
||||
$feature_defines .= " \"${define}\", //no-check-names\n";
|
||||
$feature_defines .= "#endif /* MBEDTLS_${define} */\n";
|
||||
}
|
||||
|
||||
if (!$in_section) {
|
||||
my ($section_name) = $line =~ /SECTION: ([\w ]+)/;
|
||||
my $found_section = grep $_ eq $section_name, @sections;
|
||||
|
||||
$in_section = 1 if ($found_section);
|
||||
}
|
||||
};
|
||||
|
||||
$feature_format =~ s/FEATURE_DEFINES\n/$feature_defines/g;
|
||||
|
||||
open(ERROR_FILE, ">$feature_file") or die "Opening destination file '$feature_file': $!";
|
||||
print ERROR_FILE $feature_format;
|
||||
close(ERROR_FILE);
|
||||
@@ -1,334 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Generate psa_constant_names_generated.c
|
||||
which is included by programs/psa/psa_constant_names.c.
|
||||
The code generated by this module is only meant to be used in the context
|
||||
of that program.
|
||||
|
||||
An argument passed to this script will modify the output directory where the
|
||||
file is written:
|
||||
* by default (no arguments passed): writes to programs/psa/
|
||||
* OUTPUT_FILE_DIR passed: writes to OUTPUT_FILE_DIR/
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import build_tree
|
||||
from mbedtls_framework import macro_collector
|
||||
|
||||
OUTPUT_TEMPLATE = '''\
|
||||
/* Automatically generated by generate_psa_constant.py. DO NOT EDIT. */
|
||||
|
||||
static const char *psa_strerror(psa_status_t status)
|
||||
{
|
||||
switch (status) {
|
||||
%(status_cases)s
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *psa_ecc_family_name(psa_ecc_family_t curve)
|
||||
{
|
||||
switch (curve) {
|
||||
%(ecc_curve_cases)s
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *psa_dh_family_name(psa_dh_family_t group)
|
||||
{
|
||||
switch (group) {
|
||||
%(dh_group_cases)s
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *psa_hash_algorithm_name(psa_algorithm_t hash_alg)
|
||||
{
|
||||
switch (hash_alg) {
|
||||
%(hash_algorithm_cases)s
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *psa_ka_algorithm_name(psa_algorithm_t ka_alg)
|
||||
{
|
||||
switch (ka_alg) {
|
||||
%(ka_algorithm_cases)s
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int psa_snprint_key_type(char *buffer, size_t buffer_size,
|
||||
psa_key_type_t type)
|
||||
{
|
||||
size_t required_size = 0;
|
||||
switch (type) {
|
||||
%(key_type_cases)s
|
||||
default:
|
||||
%(key_type_code)s{
|
||||
return snprintf(buffer, buffer_size,
|
||||
"0x%%04x", (unsigned) type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
buffer[0] = 0;
|
||||
return (int) required_size;
|
||||
}
|
||||
|
||||
#define NO_LENGTH_MODIFIER 0xfffffffflu
|
||||
static int psa_snprint_algorithm(char *buffer, size_t buffer_size,
|
||||
psa_algorithm_t alg)
|
||||
{
|
||||
size_t required_size = 0;
|
||||
psa_algorithm_t core_alg = alg;
|
||||
unsigned long length_modifier = NO_LENGTH_MODIFIER;
|
||||
if (PSA_ALG_IS_MAC(alg)) {
|
||||
core_alg = PSA_ALG_TRUNCATED_MAC(alg, 0);
|
||||
if (alg & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) {
|
||||
append(&buffer, buffer_size, &required_size,
|
||||
"PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(", 33);
|
||||
length_modifier = PSA_MAC_TRUNCATED_LENGTH(alg);
|
||||
} else if (core_alg != alg) {
|
||||
append(&buffer, buffer_size, &required_size,
|
||||
"PSA_ALG_TRUNCATED_MAC(", 22);
|
||||
length_modifier = PSA_MAC_TRUNCATED_LENGTH(alg);
|
||||
}
|
||||
} else if (PSA_ALG_IS_AEAD(alg)) {
|
||||
core_alg = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg);
|
||||
if (core_alg == 0) {
|
||||
/* For unknown AEAD algorithms, there is no "default tag length". */
|
||||
core_alg = alg;
|
||||
} else if (alg & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) {
|
||||
append(&buffer, buffer_size, &required_size,
|
||||
"PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(", 43);
|
||||
length_modifier = PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
|
||||
} else if (core_alg != alg) {
|
||||
append(&buffer, buffer_size, &required_size,
|
||||
"PSA_ALG_AEAD_WITH_SHORTENED_TAG(", 32);
|
||||
length_modifier = PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
|
||||
}
|
||||
} else if (PSA_ALG_IS_KEY_AGREEMENT(alg) &&
|
||||
!PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) {
|
||||
core_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF(alg);
|
||||
append(&buffer, buffer_size, &required_size,
|
||||
"PSA_ALG_KEY_AGREEMENT(", 22);
|
||||
append_with_alg(&buffer, buffer_size, &required_size,
|
||||
psa_ka_algorithm_name,
|
||||
PSA_ALG_KEY_AGREEMENT_GET_BASE(alg));
|
||||
append(&buffer, buffer_size, &required_size, ", ", 2);
|
||||
}
|
||||
switch (core_alg) {
|
||||
%(algorithm_cases)s
|
||||
default:
|
||||
%(algorithm_code)s{
|
||||
append_integer(&buffer, buffer_size, &required_size,
|
||||
"0x%%08lx", (unsigned long) core_alg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (core_alg != alg) {
|
||||
if (length_modifier != NO_LENGTH_MODIFIER) {
|
||||
append(&buffer, buffer_size, &required_size, ", ", 2);
|
||||
append_integer(&buffer, buffer_size, &required_size,
|
||||
"%%lu", length_modifier);
|
||||
}
|
||||
append(&buffer, buffer_size, &required_size, ")", 1);
|
||||
}
|
||||
buffer[0] = 0;
|
||||
return (int) required_size;
|
||||
}
|
||||
|
||||
static int psa_snprint_key_usage(char *buffer, size_t buffer_size,
|
||||
psa_key_usage_t usage)
|
||||
{
|
||||
size_t required_size = 0;
|
||||
if (usage == 0) {
|
||||
if (buffer_size > 1) {
|
||||
buffer[0] = '0';
|
||||
buffer[1] = 0;
|
||||
} else if (buffer_size == 1) {
|
||||
buffer[0] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
%(key_usage_code)s
|
||||
if (usage != 0) {
|
||||
if (required_size != 0) {
|
||||
append(&buffer, buffer_size, &required_size, " | ", 3);
|
||||
}
|
||||
append_integer(&buffer, buffer_size, &required_size,
|
||||
"0x%%08lx", (unsigned long) usage);
|
||||
} else {
|
||||
buffer[0] = 0;
|
||||
}
|
||||
return (int) required_size;
|
||||
}
|
||||
|
||||
/* End of automatically generated file. */
|
||||
'''
|
||||
|
||||
KEY_TYPE_FROM_CURVE_TEMPLATE = '''if (%(tester)s(type)) {
|
||||
append_with_curve(&buffer, buffer_size, &required_size,
|
||||
"%(builder)s", %(builder_length)s,
|
||||
PSA_KEY_TYPE_ECC_GET_FAMILY(type));
|
||||
} else '''
|
||||
|
||||
KEY_TYPE_FROM_GROUP_TEMPLATE = '''if (%(tester)s(type)) {
|
||||
append_with_group(&buffer, buffer_size, &required_size,
|
||||
"%(builder)s", %(builder_length)s,
|
||||
PSA_KEY_TYPE_DH_GET_FAMILY(type));
|
||||
} else '''
|
||||
|
||||
ALGORITHM_FROM_HASH_TEMPLATE = '''if (%(tester)s(core_alg)) {
|
||||
append(&buffer, buffer_size, &required_size,
|
||||
"%(builder)s(", %(builder_length)s + 1);
|
||||
append_with_alg(&buffer, buffer_size, &required_size,
|
||||
psa_hash_algorithm_name,
|
||||
PSA_ALG_GET_HASH(core_alg));
|
||||
append(&buffer, buffer_size, &required_size, ")", 1);
|
||||
} else '''
|
||||
|
||||
BIT_TEST_TEMPLATE = '''\
|
||||
if (%(var)s & %(flag)s) {
|
||||
if (required_size != 0) {
|
||||
append(&buffer, buffer_size, &required_size, " | ", 3);
|
||||
}
|
||||
append(&buffer, buffer_size, &required_size, "%(flag)s", %(length)d);
|
||||
%(var)s ^= %(flag)s;
|
||||
}\
|
||||
'''
|
||||
|
||||
class CaseBuilder(macro_collector.PSAMacroCollector):
|
||||
"""Collect PSA crypto macro definitions and write value recognition functions.
|
||||
|
||||
1. Call `read_file` on the input header file(s).
|
||||
2. Call `write_file` to write ``psa_constant_names_generated.c``.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(include_intermediate=True)
|
||||
|
||||
@staticmethod
|
||||
def _make_return_case(name):
|
||||
return 'case %(name)s: return "%(name)s";' % {'name': name}
|
||||
|
||||
@staticmethod
|
||||
def _make_append_case(name):
|
||||
template = ('case %(name)s: '
|
||||
'append(&buffer, buffer_size, &required_size, "%(name)s", %(length)d); '
|
||||
'break;')
|
||||
return template % {'name': name, 'length': len(name)}
|
||||
|
||||
@staticmethod
|
||||
def _make_bit_test(var, flag):
|
||||
return BIT_TEST_TEMPLATE % {'var': var,
|
||||
'flag': flag,
|
||||
'length': len(flag)}
|
||||
|
||||
def _make_status_cases(self):
|
||||
return '\n '.join(map(self._make_return_case,
|
||||
sorted(self.statuses)))
|
||||
|
||||
def _make_ecc_curve_cases(self):
|
||||
return '\n '.join(map(self._make_return_case,
|
||||
sorted(self.ecc_curves)))
|
||||
|
||||
def _make_dh_group_cases(self):
|
||||
return '\n '.join(map(self._make_return_case,
|
||||
sorted(self.dh_groups)))
|
||||
|
||||
def _make_key_type_cases(self):
|
||||
return '\n '.join(map(self._make_append_case,
|
||||
sorted(self.key_types)))
|
||||
|
||||
@staticmethod
|
||||
def _make_key_type_from_curve_code(builder, tester):
|
||||
return KEY_TYPE_FROM_CURVE_TEMPLATE % {'builder': builder,
|
||||
'builder_length': len(builder),
|
||||
'tester': tester}
|
||||
|
||||
@staticmethod
|
||||
def _make_key_type_from_group_code(builder, tester):
|
||||
return KEY_TYPE_FROM_GROUP_TEMPLATE % {'builder': builder,
|
||||
'builder_length': len(builder),
|
||||
'tester': tester}
|
||||
|
||||
def _make_ecc_key_type_code(self):
|
||||
d = self.key_types_from_curve
|
||||
make = self._make_key_type_from_curve_code
|
||||
return ''.join([make(k, d[k]) for k in sorted(d.keys())])
|
||||
|
||||
def _make_dh_key_type_code(self):
|
||||
d = self.key_types_from_group
|
||||
make = self._make_key_type_from_group_code
|
||||
return ''.join([make(k, d[k]) for k in sorted(d.keys())])
|
||||
|
||||
def _make_hash_algorithm_cases(self):
|
||||
return '\n '.join(map(self._make_return_case,
|
||||
sorted(self.hash_algorithms)))
|
||||
|
||||
def _make_ka_algorithm_cases(self):
|
||||
return '\n '.join(map(self._make_return_case,
|
||||
sorted(self.ka_algorithms)))
|
||||
|
||||
def _make_algorithm_cases(self):
|
||||
return '\n '.join(map(self._make_append_case,
|
||||
sorted(self.algorithms)))
|
||||
|
||||
@staticmethod
|
||||
def _make_algorithm_from_hash_code(builder, tester):
|
||||
return ALGORITHM_FROM_HASH_TEMPLATE % {'builder': builder,
|
||||
'builder_length': len(builder),
|
||||
'tester': tester}
|
||||
|
||||
def _make_algorithm_code(self):
|
||||
d = self.algorithms_from_hash
|
||||
make = self._make_algorithm_from_hash_code
|
||||
return ''.join([make(k, d[k]) for k in sorted(d.keys())])
|
||||
|
||||
def _make_key_usage_code(self):
|
||||
return '\n'.join([self._make_bit_test('usage', bit)
|
||||
for bit in sorted(self.key_usage_flags)])
|
||||
|
||||
def write_file(self, output_file):
|
||||
"""Generate the pretty-printer function code from the gathered
|
||||
constant definitions.
|
||||
"""
|
||||
data = {}
|
||||
data['status_cases'] = self._make_status_cases()
|
||||
data['ecc_curve_cases'] = self._make_ecc_curve_cases()
|
||||
data['dh_group_cases'] = self._make_dh_group_cases()
|
||||
data['key_type_cases'] = self._make_key_type_cases()
|
||||
data['key_type_code'] = (self._make_ecc_key_type_code() +
|
||||
self._make_dh_key_type_code())
|
||||
data['hash_algorithm_cases'] = self._make_hash_algorithm_cases()
|
||||
data['ka_algorithm_cases'] = self._make_ka_algorithm_cases()
|
||||
data['algorithm_cases'] = self._make_algorithm_cases()
|
||||
data['algorithm_code'] = self._make_algorithm_code()
|
||||
data['key_usage_code'] = self._make_key_usage_code()
|
||||
output_file.write(OUTPUT_TEMPLATE % data)
|
||||
|
||||
def generate_psa_constants(header_file_names, output_file_name):
|
||||
collector = CaseBuilder()
|
||||
for header_file_name in header_file_names:
|
||||
with open(header_file_name, 'rb') as header_file:
|
||||
collector.read_file(header_file)
|
||||
temp_file_name = output_file_name + '.tmp'
|
||||
with open(temp_file_name, 'w') as output_file:
|
||||
collector.write_file(output_file)
|
||||
os.replace(temp_file_name, output_file_name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
build_tree.chdir_to_root()
|
||||
# Allow to change the directory where psa_constant_names_generated.c is written to.
|
||||
OUTPUT_FILE_DIR = sys.argv[1] if len(sys.argv) == 2 else "programs/psa"
|
||||
|
||||
generate_psa_constants(['tf-psa-crypto/include/psa/crypto_values.h',
|
||||
'tf-psa-crypto/include/psa/crypto_extra.h'],
|
||||
OUTPUT_FILE_DIR + '/psa_constant_names_generated.c')
|
||||
@@ -1,116 +0,0 @@
|
||||
#! /usr/bin/env perl
|
||||
|
||||
# Generate query_config.c
|
||||
#
|
||||
# The file query_config.c contains a C function that can be used to check if
|
||||
# a configuration macro is defined and to retrieve its expansion in string
|
||||
# form (if any). This facilitates querying the compile time configuration of
|
||||
# the library, for example, for testing.
|
||||
#
|
||||
# The query_config.c is generated from the default configuration files
|
||||
# include/mbedtls/mbedtls_config.h and include/psa/crypto_config.h.
|
||||
# The idea is that mbedtls_config.h and crypto_config.h contain ALL the
|
||||
# compile time configurations available in Mbed TLS (commented or uncommented).
|
||||
# This script extracts the configuration macros from the two files and this
|
||||
# information is used to automatically generate the body of the query_config()
|
||||
# function by using the template in scripts/data_files/query_config.fmt.
|
||||
#
|
||||
# Usage: scripts/generate_query_config.pl without arguments, or
|
||||
# generate_query_config.pl mbedtls_config_file psa_crypto_config_file template_file output_file
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
use strict;
|
||||
|
||||
my ($mbedtls_config_file, $psa_crypto_config_file, $query_config_format_file, $query_config_file);
|
||||
|
||||
my $default_mbedtls_config_file = "./include/mbedtls/mbedtls_config.h";
|
||||
my $default_psa_crypto_config_file = "./tf-psa-crypto/include/psa/crypto_config.h";
|
||||
my $default_query_config_format_file = "./scripts/data_files/query_config.fmt";
|
||||
my $default_query_config_file = "./programs/test/query_config.c";
|
||||
|
||||
if( @ARGV ) {
|
||||
die "Invalid number of arguments - usage: $0 [MBED_TLS_CONFIG_FILE PSA_CRYPTO_CONFIG_FILE TEMPLATE_FILE OUTPUT_FILE]" if scalar @ARGV != 4;
|
||||
($mbedtls_config_file, $psa_crypto_config_file, $query_config_format_file, $query_config_file) = @ARGV;
|
||||
|
||||
-f $mbedtls_config_file or die "No such file: $mbedtls_config_file";
|
||||
-f $psa_crypto_config_file or die "No such file: $psa_crypto_config_file";
|
||||
-f $query_config_format_file or die "No such file: $query_config_format_file";
|
||||
} else {
|
||||
$mbedtls_config_file = $default_mbedtls_config_file;
|
||||
$psa_crypto_config_file = $default_psa_crypto_config_file;
|
||||
$query_config_format_file = $default_query_config_format_file;
|
||||
$query_config_file = $default_query_config_file;
|
||||
|
||||
unless(-f $mbedtls_config_file && -f $query_config_format_file && -f $psa_crypto_config_file) {
|
||||
chdir '..' or die;
|
||||
-f $mbedtls_config_file && -f $query_config_format_file && -f $psa_crypto_config_file
|
||||
or die "No arguments supplied, must be run from project root or a first-level subdirectory\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Excluded macros from the generated query_config.c. For example, macros that
|
||||
# have commas or function-like macros cannot be transformed into strings easily
|
||||
# using the preprocessor, so they should be excluded or the preprocessor will
|
||||
# throw errors.
|
||||
my @excluded = qw(
|
||||
MBEDTLS_SSL_CIPHERSUITES
|
||||
);
|
||||
my $excluded_re = join '|', @excluded;
|
||||
|
||||
# This variable will contain the string to replace in the CHECK_CONFIG of the
|
||||
# format file
|
||||
my $config_check = "";
|
||||
my $list_config = "";
|
||||
|
||||
for my $config_file ($mbedtls_config_file, $psa_crypto_config_file) {
|
||||
|
||||
next unless defined($config_file); # we might not have been given a PSA crypto config file
|
||||
|
||||
open(CONFIG_FILE, "<", $config_file) or die "Opening config file '$config_file': $!";
|
||||
|
||||
while (my $line = <CONFIG_FILE>) {
|
||||
if ($line =~ /^(\/\/)?\s*#\s*define\s+(MBEDTLS_\w+|PSA_WANT_\w+).*/) {
|
||||
my $name = $2;
|
||||
|
||||
# Skip over the macro if it is in the excluded list
|
||||
next if $name =~ /$excluded_re/;
|
||||
|
||||
$config_check .= <<EOT;
|
||||
#if defined($name)
|
||||
if( strcmp( "$name", config ) == 0 )
|
||||
{
|
||||
MACRO_EXPANSION_TO_STR( $name );
|
||||
return( 0 );
|
||||
}
|
||||
#endif /* $name */
|
||||
|
||||
EOT
|
||||
|
||||
$list_config .= <<EOT;
|
||||
#if defined($name)
|
||||
OUTPUT_MACRO_NAME_VALUE($name);
|
||||
#endif /* $name */
|
||||
|
||||
EOT
|
||||
}
|
||||
}
|
||||
|
||||
close(CONFIG_FILE);
|
||||
}
|
||||
|
||||
# Read the full format file into a string
|
||||
local $/;
|
||||
open(FORMAT_FILE, "<", $query_config_format_file) or die "Opening query config format file '$query_config_format_file': $!";
|
||||
my $query_config_format = <FORMAT_FILE>;
|
||||
close(FORMAT_FILE);
|
||||
|
||||
# Replace the body of the query_config() function with the code we just wrote
|
||||
$query_config_format =~ s/CHECK_CONFIG/$config_check/g;
|
||||
$query_config_format =~ s/LIST_CONFIG/$list_config/g;
|
||||
|
||||
# Rewrite the query_config.c file
|
||||
open(QUERY_CONFIG_FILE, ">", $query_config_file) or die "Opening destination file '$query_config_file': $!";
|
||||
print QUERY_CONFIG_FILE $query_config_format;
|
||||
close(QUERY_CONFIG_FILE);
|
||||
@@ -1,416 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Generate library/ssl_debug_helpers_generated.c
|
||||
|
||||
The code generated by this module includes debug helper functions that can not be
|
||||
implemented by fixed codes.
|
||||
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import textwrap
|
||||
import argparse
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import build_tree
|
||||
|
||||
|
||||
def remove_c_comments(string):
|
||||
"""
|
||||
Remove C style comments from input string
|
||||
"""
|
||||
string_pattern = r"(?P<string>\".*?\"|\'.*?\')"
|
||||
comment_pattern = r"(?P<comment>/\*.*?\*/|//[^\r\n]*$)"
|
||||
pattern = re.compile(string_pattern + r'|' + comment_pattern,
|
||||
re.MULTILINE | re.DOTALL)
|
||||
|
||||
def replacer(match):
|
||||
if match.lastgroup == 'comment':
|
||||
return ""
|
||||
return match.group()
|
||||
return pattern.sub(replacer, string)
|
||||
|
||||
|
||||
class CondDirectiveNotMatch(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def preprocess_c_source_code(source, *classes):
|
||||
"""
|
||||
Simple preprocessor for C source code.
|
||||
|
||||
Only processes condition directives without expanding them.
|
||||
Yield object according to the classes input. Most match firstly
|
||||
|
||||
If the directive pair does not match , raise CondDirectiveNotMatch.
|
||||
|
||||
Assume source code does not include comments and compile pass.
|
||||
|
||||
"""
|
||||
|
||||
pattern = re.compile(r"^[ \t]*#[ \t]*" +
|
||||
r"(?P<directive>(if[ \t]|ifndef[ \t]|ifdef[ \t]|else|endif))" +
|
||||
r"[ \t]*(?P<param>(.*\\\n)*.*$)",
|
||||
re.MULTILINE)
|
||||
stack = []
|
||||
|
||||
def _yield_objects(s, d, p, st, end):
|
||||
"""
|
||||
Output matched source piece
|
||||
"""
|
||||
nonlocal stack
|
||||
start_line, end_line = '', ''
|
||||
if stack:
|
||||
start_line = '#{} {}'.format(d, p)
|
||||
if d == 'if':
|
||||
end_line = '#endif /* {} */'.format(p)
|
||||
elif d == 'ifdef':
|
||||
end_line = '#endif /* defined({}) */'.format(p)
|
||||
else:
|
||||
end_line = '#endif /* !defined({}) */'.format(p)
|
||||
has_instance = False
|
||||
for cls in classes:
|
||||
for instance in cls.extract(s, st, end):
|
||||
if has_instance is False:
|
||||
has_instance = True
|
||||
yield pair_start, start_line
|
||||
yield instance.span()[0], instance
|
||||
if has_instance:
|
||||
yield start, end_line
|
||||
|
||||
for match in pattern.finditer(source):
|
||||
|
||||
directive = match.groupdict()['directive'].strip()
|
||||
param = match.groupdict()['param']
|
||||
start, end = match.span()
|
||||
|
||||
if directive in ('if', 'ifndef', 'ifdef'):
|
||||
stack.append((directive, param, start, end))
|
||||
continue
|
||||
|
||||
if not stack:
|
||||
raise CondDirectiveNotMatch()
|
||||
|
||||
pair_directive, pair_param, pair_start, pair_end = stack.pop()
|
||||
yield from _yield_objects(source,
|
||||
pair_directive,
|
||||
pair_param,
|
||||
pair_end,
|
||||
start)
|
||||
|
||||
if directive == 'endif':
|
||||
continue
|
||||
|
||||
if pair_directive == 'if':
|
||||
directive = 'if'
|
||||
param = "!( {} )".format(pair_param)
|
||||
elif pair_directive == 'ifdef':
|
||||
directive = 'ifndef'
|
||||
param = pair_param
|
||||
else:
|
||||
directive = 'ifdef'
|
||||
param = pair_param
|
||||
|
||||
stack.append((directive, param, start, end))
|
||||
assert not stack, len(stack)
|
||||
|
||||
|
||||
class EnumDefinition:
|
||||
"""
|
||||
Generate helper functions around enumeration.
|
||||
|
||||
Currently, it generate translation function from enum value to string.
|
||||
Enum definition looks like:
|
||||
[typedef] enum [prefix name] { [body] } [suffix name];
|
||||
|
||||
Known limitation:
|
||||
- the '}' and ';' SHOULD NOT exist in different macro blocks. Like
|
||||
```
|
||||
enum test {
|
||||
....
|
||||
#if defined(A)
|
||||
....
|
||||
};
|
||||
#else
|
||||
....
|
||||
};
|
||||
#endif
|
||||
```
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def extract(cls, source_code, start=0, end=-1):
|
||||
enum_pattern = re.compile(r'enum\s*(?P<prefix_name>\w*)\s*' +
|
||||
r'{\s*(?P<body>[^}]*)}' +
|
||||
r'\s*(?P<suffix_name>\w*)\s*;',
|
||||
re.MULTILINE | re.DOTALL)
|
||||
|
||||
for match in enum_pattern.finditer(source_code, start, end):
|
||||
yield EnumDefinition(source_code,
|
||||
span=match.span(),
|
||||
group=match.groupdict())
|
||||
|
||||
def __init__(self, source_code, span=None, group=None):
|
||||
assert isinstance(group, dict)
|
||||
prefix_name = group.get('prefix_name', None)
|
||||
suffix_name = group.get('suffix_name', None)
|
||||
body = group.get('body', None)
|
||||
assert prefix_name or suffix_name
|
||||
assert body
|
||||
assert span
|
||||
# If suffix_name exists, it is a typedef
|
||||
self._prototype = suffix_name if suffix_name else 'enum ' + prefix_name
|
||||
self._name = suffix_name if suffix_name else prefix_name
|
||||
self._body = body
|
||||
self._source = source_code
|
||||
self._span = span
|
||||
|
||||
def __repr__(self):
|
||||
return 'Enum({},{})'.format(self._name, self._span)
|
||||
|
||||
def __str__(self):
|
||||
return repr(self)
|
||||
|
||||
def span(self):
|
||||
return self._span
|
||||
|
||||
def generate_translation_function(self):
|
||||
"""
|
||||
Generate function for translating value to string
|
||||
"""
|
||||
translation_table = []
|
||||
|
||||
for line in self._body.splitlines():
|
||||
|
||||
if line.strip().startswith('#'):
|
||||
# Preprocess directive, keep it in table
|
||||
translation_table.append(line.strip())
|
||||
continue
|
||||
|
||||
if not line.strip():
|
||||
continue
|
||||
|
||||
for field in line.strip().split(','):
|
||||
if not field.strip():
|
||||
continue
|
||||
member = field.strip().split()[0]
|
||||
translation_table.append(
|
||||
'{space}case {member}:\n{space} return "{member}";'
|
||||
.format(member=member, space=' '*8)
|
||||
)
|
||||
|
||||
body = textwrap.dedent('''\
|
||||
const char *{name}_str( {prototype} in )
|
||||
{{
|
||||
switch (in) {{
|
||||
{translation_table}
|
||||
default:
|
||||
return "UNKNOWN_VALUE";
|
||||
}}
|
||||
}}
|
||||
''')
|
||||
body = body.format(translation_table='\n'.join(translation_table),
|
||||
name=self._name,
|
||||
prototype=self._prototype)
|
||||
return body
|
||||
|
||||
|
||||
class SignatureAlgorithmDefinition:
|
||||
"""
|
||||
Generate helper functions for signature algorithms.
|
||||
|
||||
It generates translation function from signature algorithm define to string.
|
||||
Signature algorithm definition looks like:
|
||||
#define MBEDTLS_TLS1_3_SIG_[ upper case signature algorithm ] [ value(hex) ]
|
||||
|
||||
Known limitation:
|
||||
- the definitions SHOULD exist in same macro blocks.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def extract(cls, source_code, start=0, end=-1):
|
||||
sig_alg_pattern = re.compile(r'#define\s+(?P<name>MBEDTLS_TLS1_3_SIG_\w+)\s+' +
|
||||
r'(?P<value>0[xX][0-9a-fA-F]+)$',
|
||||
re.MULTILINE | re.DOTALL)
|
||||
matches = list(sig_alg_pattern.finditer(source_code, start, end))
|
||||
if matches:
|
||||
yield SignatureAlgorithmDefinition(source_code, definitions=matches)
|
||||
|
||||
def __init__(self, source_code, definitions=None):
|
||||
if definitions is None:
|
||||
definitions = []
|
||||
assert isinstance(definitions, list) and definitions
|
||||
self._definitions = definitions
|
||||
self._source = source_code
|
||||
|
||||
def __repr__(self):
|
||||
return 'SigAlgs({})'.format(self._definitions[0].span())
|
||||
|
||||
def span(self):
|
||||
return self._definitions[0].span()
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Generate function for translating value to string
|
||||
"""
|
||||
translation_table = []
|
||||
for m in self._definitions:
|
||||
name = m.groupdict()['name']
|
||||
return_val = name[len('MBEDTLS_TLS1_3_SIG_'):].lower()
|
||||
translation_table.append(
|
||||
' case {}:\n return "{}";'.format(name, return_val))
|
||||
|
||||
body = textwrap.dedent('''\
|
||||
const char *mbedtls_ssl_sig_alg_to_str( uint16_t in )
|
||||
{{
|
||||
switch( in )
|
||||
{{
|
||||
{translation_table}
|
||||
}};
|
||||
|
||||
return "UNKNOWN";
|
||||
}}''')
|
||||
body = body.format(translation_table='\n'.join(translation_table))
|
||||
return body
|
||||
|
||||
|
||||
class NamedGroupDefinition:
|
||||
"""
|
||||
Generate helper functions for named group
|
||||
|
||||
It generates translation function from named group define to string.
|
||||
Named group definition looks like:
|
||||
#define MBEDTLS_SSL_IANA_TLS_GROUP_[ upper case named group ] [ value(hex) ]
|
||||
|
||||
Known limitation:
|
||||
- the definitions SHOULD exist in same macro blocks.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def extract(cls, source_code, start=0, end=-1):
|
||||
named_group_pattern = re.compile(r'#define\s+(?P<name>MBEDTLS_SSL_IANA_TLS_GROUP_\w+)\s+' +
|
||||
r'(?P<value>0[xX][0-9a-fA-F]+)$',
|
||||
re.MULTILINE | re.DOTALL)
|
||||
matches = list(named_group_pattern.finditer(source_code, start, end))
|
||||
if matches:
|
||||
yield NamedGroupDefinition(source_code, definitions=matches)
|
||||
|
||||
def __init__(self, source_code, definitions=None):
|
||||
if definitions is None:
|
||||
definitions = []
|
||||
assert isinstance(definitions, list) and definitions
|
||||
self._definitions = definitions
|
||||
self._source = source_code
|
||||
|
||||
def __repr__(self):
|
||||
return 'NamedGroup({})'.format(self._definitions[0].span())
|
||||
|
||||
def span(self):
|
||||
return self._definitions[0].span()
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Generate function for translating value to string
|
||||
"""
|
||||
translation_table = []
|
||||
for m in self._definitions:
|
||||
name = m.groupdict()['name']
|
||||
iana_name = name[len('MBEDTLS_SSL_IANA_TLS_GROUP_'):].lower()
|
||||
translation_table.append(' case {}:\n return "{}";'.format(name, iana_name))
|
||||
|
||||
body = textwrap.dedent('''\
|
||||
const char *mbedtls_ssl_named_group_to_str( uint16_t in )
|
||||
{{
|
||||
switch( in )
|
||||
{{
|
||||
{translation_table}
|
||||
}};
|
||||
|
||||
return "UNKNOWN";
|
||||
}}''')
|
||||
body = body.format(translation_table='\n'.join(translation_table))
|
||||
return body
|
||||
|
||||
|
||||
OUTPUT_C_TEMPLATE = '''\
|
||||
/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */
|
||||
|
||||
/**
|
||||
* \\file ssl_debug_helpers_generated.c
|
||||
*
|
||||
* \\brief Automatically generated helper functions for debugging
|
||||
*/
|
||||
/*
|
||||
* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(MBEDTLS_DEBUG_C)
|
||||
|
||||
#include "ssl_debug_helpers.h"
|
||||
|
||||
{functions}
|
||||
|
||||
#endif /* MBEDTLS_DEBUG_C */
|
||||
/* End of automatically generated file. */
|
||||
|
||||
'''
|
||||
|
||||
|
||||
def generate_ssl_debug_helpers(output_directory, mbedtls_root):
|
||||
"""
|
||||
Generate functions of debug helps
|
||||
"""
|
||||
mbedtls_root = os.path.abspath(
|
||||
mbedtls_root or build_tree.guess_mbedtls_root())
|
||||
with open(os.path.join(mbedtls_root, 'include/mbedtls/ssl.h')) as f:
|
||||
source_code = remove_c_comments(f.read())
|
||||
|
||||
definitions = dict()
|
||||
for start, instance in preprocess_c_source_code(source_code,
|
||||
EnumDefinition,
|
||||
SignatureAlgorithmDefinition,
|
||||
NamedGroupDefinition):
|
||||
if start in definitions:
|
||||
continue
|
||||
if isinstance(instance, EnumDefinition):
|
||||
definition = instance.generate_translation_function()
|
||||
else:
|
||||
definition = instance
|
||||
definitions[start] = definition
|
||||
|
||||
function_definitions = [str(v) for _, v in sorted(definitions.items())]
|
||||
if output_directory == sys.stdout:
|
||||
sys.stdout.write(OUTPUT_C_TEMPLATE.format(
|
||||
functions='\n'.join(function_definitions)))
|
||||
else:
|
||||
with open(os.path.join(output_directory, 'ssl_debug_helpers_generated.c'), 'w') as f:
|
||||
f.write(OUTPUT_C_TEMPLATE.format(
|
||||
functions='\n'.join(function_definitions)))
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Command line entry
|
||||
"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--mbedtls-root', nargs='?', default=None,
|
||||
help='root directory of mbedtls source code')
|
||||
parser.add_argument('output_directory', nargs='?',
|
||||
default='library', help='source/header files location')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
generate_ssl_debug_helpers(args.output_directory, args.mbedtls_root)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,304 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Generate main file, individual apps and solution files for
|
||||
# MS Visual Studio 2017
|
||||
#
|
||||
# Must be run from Mbed TLS root or scripts directory.
|
||||
# Takes no argument.
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use Digest::MD5 'md5_hex';
|
||||
|
||||
my $vsx_dir = "visualc/VS2017";
|
||||
my $vsx_ext = "vcxproj";
|
||||
my $vsx_app_tpl_file = "scripts/data_files/vs2017-app-template.$vsx_ext";
|
||||
my $vsx_main_tpl_file = "scripts/data_files/vs2017-main-template.$vsx_ext";
|
||||
my $vsx_main_file = "$vsx_dir/mbedTLS.$vsx_ext";
|
||||
my $vsx_sln_tpl_file = "scripts/data_files/vs2017-sln-template.sln";
|
||||
my $vsx_sln_file = "$vsx_dir/mbedTLS.sln";
|
||||
|
||||
my $programs_dir = 'programs';
|
||||
my $mbedtls_header_dir = 'include/mbedtls';
|
||||
my $drivers_builtin_header_dir = 'tf-psa-crypto/drivers/builtin/include/mbedtls';
|
||||
my $psa_header_dir = 'tf-psa-crypto/include/psa';
|
||||
my $tls_source_dir = 'library';
|
||||
my $crypto_core_source_dir = 'tf-psa-crypto/core';
|
||||
my $crypto_source_dir = 'tf-psa-crypto/drivers/builtin/src';
|
||||
my $test_source_dir = 'tests/src';
|
||||
my $test_header_dir = 'tests/include/test';
|
||||
my $test_drivers_header_dir = 'tests/include/test/drivers';
|
||||
my $test_drivers_source_dir = 'tests/src/drivers';
|
||||
|
||||
my @thirdparty_header_dirs = qw(
|
||||
tf-psa-crypto/drivers/everest/include/everest
|
||||
);
|
||||
my @thirdparty_source_dirs = qw(
|
||||
tf-psa-crypto/drivers/everest/library
|
||||
tf-psa-crypto/drivers/everest/library/kremlib
|
||||
tf-psa-crypto/drivers/everest/library/legacy
|
||||
);
|
||||
|
||||
# Directories to add to the include path.
|
||||
# Order matters in case there are files with the same name in more than
|
||||
# one directory: the compiler will use the first match.
|
||||
my @include_directories = qw(
|
||||
include
|
||||
tf-psa-crypto/include
|
||||
tf-psa-crypto/drivers/builtin/include
|
||||
tf-psa-crypto/drivers/everest/include/
|
||||
tf-psa-crypto/drivers/everest/include/everest
|
||||
tf-psa-crypto/drivers/everest/include/everest/vs2013
|
||||
tf-psa-crypto/drivers/everest/include/everest/kremlib
|
||||
tests/include
|
||||
);
|
||||
my $include_directories = join(';', map {"../../$_"} @include_directories);
|
||||
|
||||
# Directories to add to the include path when building the libraries, but not
|
||||
# when building tests or applications.
|
||||
my @library_include_directories = qw(
|
||||
library
|
||||
tf-psa-crypto/core
|
||||
tf-psa-crypto/drivers/builtin/src
|
||||
);
|
||||
my $library_include_directories =
|
||||
join(';', map {"../../$_"} (@library_include_directories,
|
||||
@include_directories));
|
||||
|
||||
my @excluded_files = qw(
|
||||
tf-psa-crypto/drivers/everest/library/Hacl_Curve25519.c
|
||||
);
|
||||
my %excluded_files = ();
|
||||
foreach (@excluded_files) { $excluded_files{$_} = 1 }
|
||||
|
||||
my $vsx_hdr_tpl = <<EOT;
|
||||
<ClInclude Include="..\\..\\{NAME}" />
|
||||
EOT
|
||||
my $vsx_src_tpl = <<EOT;
|
||||
<ClCompile Include="..\\..\\{NAME}" />
|
||||
EOT
|
||||
|
||||
my $vsx_sln_app_entry_tpl = <<EOT;
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "{APPNAME}", "{APPNAME}.vcxproj", "{GUID}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
EOT
|
||||
|
||||
my $vsx_sln_conf_entry_tpl = <<EOT;
|
||||
{GUID}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{GUID}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{GUID}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{GUID}.Debug|x64.Build.0 = Debug|x64
|
||||
{GUID}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{GUID}.Release|Win32.Build.0 = Release|Win32
|
||||
{GUID}.Release|x64.ActiveCfg = Release|x64
|
||||
{GUID}.Release|x64.Build.0 = Release|x64
|
||||
EOT
|
||||
|
||||
exit( main() );
|
||||
|
||||
sub check_dirs {
|
||||
foreach my $d (@thirdparty_header_dirs, @thirdparty_source_dirs) {
|
||||
if (not (-d $d)) { return 0; }
|
||||
}
|
||||
return -d $vsx_dir
|
||||
&& -d $mbedtls_header_dir
|
||||
&& -d $drivers_builtin_header_dir
|
||||
&& -d $psa_header_dir
|
||||
&& -d $tls_source_dir
|
||||
&& -d $crypto_core_source_dir
|
||||
&& -d $crypto_source_dir
|
||||
&& -d $test_source_dir
|
||||
&& -d $test_drivers_source_dir
|
||||
&& -d $test_header_dir
|
||||
&& -d $test_drivers_header_dir
|
||||
&& -d $programs_dir;
|
||||
}
|
||||
|
||||
sub slurp_file {
|
||||
my ($filename) = @_;
|
||||
|
||||
local $/ = undef;
|
||||
open my $fh, '<:crlf', $filename or die "Could not read $filename\n";
|
||||
my $content = <$fh>;
|
||||
close $fh;
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
sub content_to_file {
|
||||
my ($content, $filename) = @_;
|
||||
|
||||
open my $fh, '>:crlf', $filename or die "Could not write to $filename\n";
|
||||
print $fh $content;
|
||||
close $fh;
|
||||
}
|
||||
|
||||
sub gen_app_guid {
|
||||
my ($path) = @_;
|
||||
|
||||
my $guid = md5_hex( "mbedTLS:$path" );
|
||||
$guid =~ s/(.{8})(.{4})(.{4})(.{4})(.{12})/\U{$1-$2-$3-$4-$5}/;
|
||||
|
||||
return $guid;
|
||||
}
|
||||
|
||||
sub gen_app {
|
||||
my ($path, $template, $dir, $ext) = @_;
|
||||
|
||||
my $guid = gen_app_guid( $path );
|
||||
$path =~ s!/!\\!g;
|
||||
(my $appname = $path) =~ s/.*\\//;
|
||||
my $is_test_app = ($path =~ m/^test\\/);
|
||||
|
||||
my $srcs = "<ClCompile Include=\"..\\..\\programs\\$path.c\" \/>";
|
||||
if( $appname eq "ssl_client2" or $appname eq "ssl_server2" or
|
||||
$appname eq "query_compile_time_config" ) {
|
||||
$srcs .= "\n <ClCompile Include=\"..\\..\\programs\\test\\query_config.c\" \/>";
|
||||
}
|
||||
if( $appname eq "ssl_client2" or $appname eq "ssl_server2" ) {
|
||||
$srcs .= "\n <ClCompile Include=\"..\\..\\programs\\ssl\\ssl_test_lib.c\" \/>";
|
||||
}
|
||||
|
||||
my $content = $template;
|
||||
$content =~ s/<SOURCES>/$srcs/g;
|
||||
$content =~ s/<APPNAME>/$appname/g;
|
||||
$content =~ s/<GUID>/$guid/g;
|
||||
$content =~ s/INCLUDE_DIRECTORIES\n/($is_test_app ?
|
||||
$library_include_directories :
|
||||
$include_directories)/ge;
|
||||
|
||||
content_to_file( $content, "$dir/$appname.$ext" );
|
||||
}
|
||||
|
||||
sub get_app_list {
|
||||
my $makefile_contents = slurp_file('programs/Makefile');
|
||||
$makefile_contents =~ /\n\s*APPS\s*=[\\\s]*(.*?)(?<!\\)[\#\n]/s
|
||||
or die "Cannot find APPS = ... in programs/Makefile\n";
|
||||
return split /(?:\s|\\)+/, $1;
|
||||
}
|
||||
|
||||
sub gen_app_files {
|
||||
my @app_list = @_;
|
||||
|
||||
my $vsx_tpl = slurp_file( $vsx_app_tpl_file );
|
||||
|
||||
for my $app ( @app_list ) {
|
||||
gen_app( $app, $vsx_tpl, $vsx_dir, $vsx_ext );
|
||||
}
|
||||
}
|
||||
|
||||
sub gen_entry_list {
|
||||
my ($tpl, @names) = @_;
|
||||
|
||||
my $entries;
|
||||
for my $name (@names) {
|
||||
(my $entry = $tpl) =~ s/{NAME}/$name/g;
|
||||
$entries .= $entry;
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
sub gen_main_file {
|
||||
my ($headers, $sources,
|
||||
$hdr_tpl, $src_tpl,
|
||||
$main_tpl, $main_out) = @_;
|
||||
|
||||
my $header_entries = gen_entry_list( $hdr_tpl, @$headers );
|
||||
my $source_entries = gen_entry_list( $src_tpl, @$sources );
|
||||
|
||||
my $out = slurp_file( $main_tpl );
|
||||
$out =~ s/SOURCE_ENTRIES\n/$source_entries/m;
|
||||
$out =~ s/HEADER_ENTRIES\n/$header_entries/m;
|
||||
$out =~ s/INCLUDE_DIRECTORIES\n/$library_include_directories/g;
|
||||
|
||||
content_to_file( $out, $main_out );
|
||||
}
|
||||
|
||||
sub gen_vsx_solution {
|
||||
my (@app_names) = @_;
|
||||
|
||||
my ($app_entries, $conf_entries);
|
||||
for my $path (@app_names) {
|
||||
my $guid = gen_app_guid( $path );
|
||||
(my $appname = $path) =~ s!.*/!!;
|
||||
|
||||
my $app_entry = $vsx_sln_app_entry_tpl;
|
||||
$app_entry =~ s/{APPNAME}/$appname/g;
|
||||
$app_entry =~ s/{GUID}/$guid/g;
|
||||
|
||||
$app_entries .= $app_entry;
|
||||
|
||||
my $conf_entry = $vsx_sln_conf_entry_tpl;
|
||||
$conf_entry =~ s/{GUID}/$guid/g;
|
||||
|
||||
$conf_entries .= $conf_entry;
|
||||
}
|
||||
|
||||
my $out = slurp_file( $vsx_sln_tpl_file );
|
||||
$out =~ s/APP_ENTRIES\n/$app_entries/m;
|
||||
$out =~ s/CONF_ENTRIES\n/$conf_entries/m;
|
||||
|
||||
content_to_file( $out, $vsx_sln_file );
|
||||
}
|
||||
|
||||
sub del_vsx_files {
|
||||
unlink glob "'$vsx_dir/*.$vsx_ext'";
|
||||
unlink $vsx_main_file;
|
||||
unlink $vsx_sln_file;
|
||||
}
|
||||
|
||||
sub main {
|
||||
if( ! check_dirs() ) {
|
||||
chdir '..' or die;
|
||||
check_dirs or die "Must be run from Mbed TLS root or scripts dir\n";
|
||||
}
|
||||
|
||||
# Remove old files to ensure that, for example, project files from deleted
|
||||
# apps are not kept
|
||||
del_vsx_files();
|
||||
|
||||
my @app_list = get_app_list();
|
||||
my @header_dirs = (
|
||||
$mbedtls_header_dir,
|
||||
$drivers_builtin_header_dir,
|
||||
$psa_header_dir,
|
||||
$test_header_dir,
|
||||
$test_drivers_header_dir,
|
||||
$tls_source_dir,
|
||||
$crypto_core_source_dir,
|
||||
$crypto_source_dir,
|
||||
@thirdparty_header_dirs,
|
||||
);
|
||||
my @headers = (map { <$_/*.h> } @header_dirs);
|
||||
my @source_dirs = (
|
||||
$tls_source_dir,
|
||||
$crypto_core_source_dir,
|
||||
$crypto_source_dir,
|
||||
$test_source_dir,
|
||||
$test_drivers_source_dir,
|
||||
@thirdparty_source_dirs,
|
||||
);
|
||||
my @sources = (map { <$_/*.c> } @source_dirs);
|
||||
|
||||
@headers = grep { ! $excluded_files{$_} } @headers;
|
||||
@sources = grep { ! $excluded_files{$_} } @sources;
|
||||
map { s!/!\\!g } @headers;
|
||||
map { s!/!\\!g } @sources;
|
||||
|
||||
gen_app_files( @app_list );
|
||||
|
||||
gen_main_file( \@headers, \@sources,
|
||||
$vsx_hdr_tpl, $vsx_src_tpl,
|
||||
$vsx_main_tpl_file, $vsx_main_file );
|
||||
|
||||
gen_vsx_solution( @app_list );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
help () {
|
||||
cat <<EOF
|
||||
Usage: $0 [-r]
|
||||
Collect coverage statistics of library code into an HTML report.
|
||||
|
||||
General instructions:
|
||||
1. Build the library with CFLAGS="--coverage -O0 -g3" and link the test
|
||||
programs with LDFLAGS="--coverage".
|
||||
This can be an out-of-tree build.
|
||||
For example (in-tree):
|
||||
make CFLAGS="--coverage -O0 -g3" LDFLAGS="--coverage"
|
||||
Or (out-of-tree):
|
||||
mkdir build-coverage && cd build-coverage &&
|
||||
cmake -D CMAKE_BUILD_TYPE=Coverage .. && make
|
||||
2. Run whatever tests you want.
|
||||
3. Run this script from the parent of the directory containing the library
|
||||
object files and coverage statistics files.
|
||||
4. Browse the coverage report in Coverage/index.html.
|
||||
5. After rework, run "$0 -r", then re-test and run "$0" to get a fresh report.
|
||||
|
||||
Options
|
||||
-r Reset traces. Run this before re-testing to get fresh measurements.
|
||||
EOF
|
||||
}
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
set -eu
|
||||
|
||||
# Project detection
|
||||
PROJECT_NAME_FILE='./scripts/project_name.txt'
|
||||
if read -r PROJECT_NAME < "$PROJECT_NAME_FILE"; then :; else
|
||||
echo "$PROJECT_NAME_FILE does not exist... Exiting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
in_mbedtls_repo () {
|
||||
test "$PROJECT_NAME" = "Mbed TLS"
|
||||
}
|
||||
|
||||
# Collect stats and build a HTML report.
|
||||
lcov_library_report () {
|
||||
rm -rf Coverage
|
||||
mkdir Coverage Coverage/tmp
|
||||
# Pass absolute paths as lcov output files. This works around a bug
|
||||
# whereby lcov tries to create the output file in the root directory
|
||||
# if it has emitted a warning. A fix was released in lcov 1.13 in 2016.
|
||||
# Ubuntu 16.04 is affected, 18.04 and above are not.
|
||||
# https://github.com/linux-test-project/lcov/commit/632c25a0d1f5e4d2f4fd5b28ce7c8b86d388c91f
|
||||
COVTMP=$PWD/Coverage/tmp
|
||||
lcov --capture --initial --directory $library_dir -o "$COVTMP/files.info"
|
||||
lcov --rc lcov_branch_coverage=1 --capture --directory $library_dir -o "$COVTMP/tests.info"
|
||||
lcov --rc lcov_branch_coverage=1 --add-tracefile "$COVTMP/files.info" --add-tracefile "$COVTMP/tests.info" -o "$COVTMP/all.info"
|
||||
lcov --rc lcov_branch_coverage=1 --remove "$COVTMP/all.info" -o "$COVTMP/final.info" '*.h'
|
||||
gendesc tests/Descriptions.txt -o "$COVTMP/descriptions"
|
||||
genhtml --title "$title" --description-file "$COVTMP/descriptions" --keep-descriptions --legend --branch-coverage -o Coverage "$COVTMP/final.info"
|
||||
rm -f "$COVTMP/"*.info "$COVTMP/descriptions"
|
||||
echo "Coverage report in: Coverage/index.html"
|
||||
}
|
||||
|
||||
# Reset the traces to 0.
|
||||
lcov_reset_traces () {
|
||||
# Location with plain make
|
||||
rm -f $library_dir/*.gcda
|
||||
# Location with CMake
|
||||
rm -f $library_dir/CMakeFiles/*.dir/*.gcda
|
||||
}
|
||||
|
||||
if [ $# -gt 0 ] && [ "$1" = "--help" ]; then
|
||||
help
|
||||
exit
|
||||
fi
|
||||
|
||||
if in_mbedtls_repo; then
|
||||
library_dir='library'
|
||||
title='Mbed TLS'
|
||||
else
|
||||
library_dir='core'
|
||||
title='TF-PSA-Crypto'
|
||||
fi
|
||||
|
||||
main=lcov_library_report
|
||||
while getopts r OPTLET; do
|
||||
case $OPTLET in
|
||||
r) main=lcov_reset_traces;;
|
||||
*) help 2>&1; exit 120;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
"$main" "$@"
|
||||
@@ -1,10 +0,0 @@
|
||||
# Python packages that are only useful to Mbed TLS maintainers.
|
||||
|
||||
-r ci.requirements.txt
|
||||
|
||||
# For source code analyses
|
||||
clang
|
||||
|
||||
# For building some test vectors
|
||||
pycryptodomex
|
||||
pycryptodome-test-vectors
|
||||
@@ -1,32 +0,0 @@
|
||||
@rem Generate automatically-generated configuration-independent source files
|
||||
@rem and build scripts.
|
||||
@rem Requirements:
|
||||
@rem * Perl must be on the PATH ("perl" command).
|
||||
@rem * Python 3.8 or above must be on the PATH ("python" command).
|
||||
@rem * Either a C compiler called "cc" must be on the PATH, or
|
||||
@rem the "CC" environment variable must point to a C compiler.
|
||||
|
||||
@rem @@@@ library\** @@@@
|
||||
@rem psa_crypto_driver_wrappers.h needs to be generated prior to
|
||||
@rem generate_visualc_files.pl being invoked.
|
||||
python scripts\generate_driver_wrappers.py || exit /b 1
|
||||
perl scripts\generate_errors.pl || exit /b 1
|
||||
perl scripts\generate_query_config.pl || exit /b 1
|
||||
perl scripts\generate_features.pl || exit /b 1
|
||||
python scripts\generate_ssl_debug_helpers.py || exit /b 1
|
||||
|
||||
@rem @@@@ Build @@@@
|
||||
perl scripts\generate_visualc_files.pl || exit /b 1
|
||||
|
||||
@rem @@@@ programs\** @@@@
|
||||
python scripts\generate_psa_constants.py || exit /b 1
|
||||
|
||||
@rem @@@@ tests\** @@@@
|
||||
python framework\scripts\generate_bignum_tests.py --directory tf-psa-crypto\tests\suites || exit /b 1
|
||||
python framework\scripts\generate_config_tests.py tests\suites\test_suite_config.mbedtls_boolean.data || exit /b 1
|
||||
python framework\scripts\generate_config_tests.py --directory tf-psa-crypto\tests\suites tests\suites\test_suite_config.psa_boolean.data || exit /b 1
|
||||
python framework\scripts\generate_ecp_tests.py --directory tf-psa-crypto\tests\suites || exit /b 1
|
||||
python framework\scripts\generate_psa_tests.py --directory tf-psa-crypto\tests\suites || exit /b 1
|
||||
python framework\scripts\generate_test_keys.py --output tests\src\test_keys.h || exit /b 1
|
||||
python framework\scripts\generate_test_cert_macros.py --output tests\src\test_certs.h || exit /b 1
|
||||
python tests\scripts\generate_tls13_compat_tests.py || exit /b 1
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Parse a massif.out.xxx file and output peak total memory usage
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use utf8;
|
||||
use open qw(:std utf8);
|
||||
|
||||
die unless @ARGV == 1;
|
||||
|
||||
my @snaps;
|
||||
open my $fh, '<', $ARGV[0] or die;
|
||||
{ local $/ = 'snapshot='; @snaps = <$fh>; }
|
||||
close $fh or die;
|
||||
|
||||
my ($max, $max_heap, $max_he, $max_stack) = (0, 0, 0, 0);
|
||||
for (@snaps)
|
||||
{
|
||||
my ($heap, $heap_extra, $stack) = m{
|
||||
mem_heap_B=(\d+)\n
|
||||
mem_heap_extra_B=(\d+)\n
|
||||
mem_stacks_B=(\d+)
|
||||
}xm;
|
||||
next unless defined $heap;
|
||||
my $total = $heap + $heap_extra + $stack;
|
||||
if( $total > $max ) {
|
||||
($max, $max_heap, $max_he, $max_stack) = ($total, $heap, $heap_extra, $stack);
|
||||
}
|
||||
}
|
||||
|
||||
printf "$max (heap $max_heap+$max_he, stack $max_stack)\n";
|
||||
@@ -0,0 +1,167 @@
|
||||
"""Discover all the test cases (unit tests and SSL tests)."""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import build_tree
|
||||
|
||||
|
||||
class ScriptOutputError(ValueError):
|
||||
"""A kind of ValueError that indicates we found
|
||||
the script doesn't list test cases in an expected
|
||||
pattern.
|
||||
"""
|
||||
|
||||
@property
|
||||
def script_name(self):
|
||||
return super().args[0]
|
||||
|
||||
@property
|
||||
def idx(self):
|
||||
return super().args[1]
|
||||
|
||||
@property
|
||||
def line(self):
|
||||
return super().args[2]
|
||||
|
||||
class Results:
|
||||
"""Store file and line information about errors or warnings in test suites."""
|
||||
|
||||
def __init__(self, options):
|
||||
self.errors = 0
|
||||
self.warnings = 0
|
||||
self.ignore_warnings = options.quiet
|
||||
|
||||
def error(self, file_name, line_number, fmt, *args):
|
||||
sys.stderr.write(('{}:{}:ERROR:' + fmt + '\n').
|
||||
format(file_name, line_number, *args))
|
||||
self.errors += 1
|
||||
|
||||
def warning(self, file_name, line_number, fmt, *args):
|
||||
if not self.ignore_warnings:
|
||||
sys.stderr.write(('{}:{}:Warning:' + fmt + '\n')
|
||||
.format(file_name, line_number, *args))
|
||||
self.warnings += 1
|
||||
|
||||
class TestDescriptionExplorer:
|
||||
"""An iterator over test cases with descriptions.
|
||||
|
||||
The test cases that have descriptions are:
|
||||
* Individual unit tests (entries in a .data file) in test suites.
|
||||
* Individual test cases in ssl-opt.sh.
|
||||
|
||||
This is an abstract class. To use it, derive a class that implements
|
||||
the process_test_case method, and call walk_all().
|
||||
"""
|
||||
|
||||
def process_test_case(self, per_file_state,
|
||||
file_name, line_number, description):
|
||||
"""Process a test case.
|
||||
|
||||
per_file_state: an object created by new_per_file_state() at the beginning
|
||||
of each file.
|
||||
file_name: a relative path to the file containing the test case.
|
||||
line_number: the line number in the given file.
|
||||
description: the test case description as a byte string.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def new_per_file_state(self):
|
||||
"""Return a new per-file state object.
|
||||
|
||||
The default per-file state object is None. Child classes that require per-file
|
||||
state may override this method.
|
||||
"""
|
||||
#pylint: disable=no-self-use
|
||||
return None
|
||||
|
||||
def walk_test_suite(self, data_file_name):
|
||||
"""Iterate over the test cases in the given unit test data file."""
|
||||
in_paragraph = False
|
||||
descriptions = self.new_per_file_state() # pylint: disable=assignment-from-none
|
||||
with open(data_file_name, 'rb') as data_file:
|
||||
for line_number, line in enumerate(data_file, 1):
|
||||
line = line.rstrip(b'\r\n')
|
||||
if not line:
|
||||
in_paragraph = False
|
||||
continue
|
||||
if line.startswith(b'#'):
|
||||
continue
|
||||
if not in_paragraph:
|
||||
# This is a test case description line.
|
||||
self.process_test_case(descriptions,
|
||||
data_file_name, line_number, line)
|
||||
in_paragraph = True
|
||||
|
||||
def collect_from_script(self, script_name):
|
||||
"""Collect the test cases in a script by calling its listing test cases
|
||||
option"""
|
||||
descriptions = self.new_per_file_state() # pylint: disable=assignment-from-none
|
||||
listed = subprocess.check_output(['sh', script_name, '--list-test-cases'])
|
||||
# Assume test file is responsible for printing identical format of
|
||||
# test case description between --list-test-cases and its OUTCOME.CSV
|
||||
#
|
||||
# idx indicates the number of test case since there is no line number
|
||||
# in the script for each test case.
|
||||
for idx, line in enumerate(listed.splitlines()):
|
||||
# We are expecting the script to list the test cases in
|
||||
# `<suite_name>;<description>` pattern.
|
||||
script_outputs = line.split(b';', 1)
|
||||
if len(script_outputs) == 2:
|
||||
suite_name, description = script_outputs
|
||||
else:
|
||||
raise ScriptOutputError(script_name, idx, line.decode("utf-8"))
|
||||
|
||||
self.process_test_case(descriptions,
|
||||
suite_name.decode('utf-8'),
|
||||
idx,
|
||||
description.rstrip())
|
||||
|
||||
@staticmethod
|
||||
def collect_test_directories():
|
||||
"""Get the relative path for the TLS and Crypto test directories."""
|
||||
mbedtls_root = build_tree.guess_mbedtls_root()
|
||||
directories = [os.path.join(mbedtls_root, 'tests'),
|
||||
os.path.join(mbedtls_root, 'tf-psa-crypto', 'tests')]
|
||||
directories = [os.path.relpath(p) for p in directories]
|
||||
return directories
|
||||
|
||||
def walk_all(self):
|
||||
"""Iterate over all named test cases."""
|
||||
test_directories = self.collect_test_directories()
|
||||
for directory in test_directories:
|
||||
for data_file_name in glob.glob(os.path.join(directory, 'suites',
|
||||
'*.data')):
|
||||
self.walk_test_suite(data_file_name)
|
||||
|
||||
for sh_file in ['ssl-opt.sh', 'compat.sh']:
|
||||
sh_file = os.path.join(directory, sh_file)
|
||||
if os.path.isfile(sh_file):
|
||||
self.collect_from_script(sh_file)
|
||||
|
||||
class TestDescriptions(TestDescriptionExplorer):
|
||||
"""Collect the available test cases."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.descriptions = set()
|
||||
|
||||
def process_test_case(self, _per_file_state,
|
||||
file_name, _line_number, description):
|
||||
"""Record an available test case."""
|
||||
base_name = re.sub(r'\.[^.]*$', '', re.sub(r'.*/', '', file_name))
|
||||
key = ';'.join([base_name, description.decode('utf-8')])
|
||||
self.descriptions.add(key)
|
||||
|
||||
def collect_available_test_cases():
|
||||
"""Collect the available test cases."""
|
||||
explorer = TestDescriptions()
|
||||
explorer.walk_all()
|
||||
return sorted(explorer.descriptions)
|
||||
@@ -0,0 +1,362 @@
|
||||
"""Outcome file analysis code.
|
||||
|
||||
This module is the bulk of the code of tests/scripts/analyze_outcomes.py
|
||||
in each consuming branch. The consuming script is expected to derive
|
||||
the classes with branch-specific customizations such as ignore lists.
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import traceback
|
||||
import re
|
||||
import subprocess
|
||||
import os
|
||||
import typing
|
||||
|
||||
import collect_test_cases
|
||||
|
||||
|
||||
# `ComponentOutcomes` is a named tuple which is defined as:
|
||||
# ComponentOutcomes(
|
||||
# successes = {
|
||||
# "<suite_case>",
|
||||
# ...
|
||||
# },
|
||||
# failures = {
|
||||
# "<suite_case>",
|
||||
# ...
|
||||
# }
|
||||
# )
|
||||
# suite_case = "<suite>;<case>"
|
||||
ComponentOutcomes = typing.NamedTuple('ComponentOutcomes',
|
||||
[('successes', typing.Set[str]),
|
||||
('failures', typing.Set[str])])
|
||||
|
||||
# `Outcomes` is a representation of the outcomes file,
|
||||
# which defined as:
|
||||
# Outcomes = {
|
||||
# "<component>": ComponentOutcomes,
|
||||
# ...
|
||||
# }
|
||||
Outcomes = typing.Dict[str, ComponentOutcomes]
|
||||
|
||||
|
||||
class Results:
|
||||
"""Process analysis results."""
|
||||
|
||||
def __init__(self):
|
||||
self.error_count = 0
|
||||
self.warning_count = 0
|
||||
|
||||
def new_section(self, fmt, *args, **kwargs):
|
||||
self._print_line('\n*** ' + fmt + ' ***\n', *args, **kwargs)
|
||||
|
||||
def info(self, fmt, *args, **kwargs):
|
||||
self._print_line('Info: ' + fmt, *args, **kwargs)
|
||||
|
||||
def error(self, fmt, *args, **kwargs):
|
||||
self.error_count += 1
|
||||
self._print_line('Error: ' + fmt, *args, **kwargs)
|
||||
|
||||
def warning(self, fmt, *args, **kwargs):
|
||||
self.warning_count += 1
|
||||
self._print_line('Warning: ' + fmt, *args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def _print_line(fmt, *args, **kwargs):
|
||||
sys.stderr.write((fmt + '\n').format(*args, **kwargs))
|
||||
|
||||
def execute_reference_driver_tests(results: Results, ref_component: str, driver_component: str, \
|
||||
outcome_file: str) -> None:
|
||||
"""Run the tests specified in ref_component and driver_component. Results
|
||||
are stored in the output_file and they will be used for the following
|
||||
coverage analysis"""
|
||||
results.new_section("Test {} and {}", ref_component, driver_component)
|
||||
|
||||
shell_command = "tests/scripts/all.sh --outcome-file " + outcome_file + \
|
||||
" " + ref_component + " " + driver_component
|
||||
results.info("Running: {}", shell_command)
|
||||
ret_val = subprocess.run(shell_command.split(), check=False).returncode
|
||||
|
||||
if ret_val != 0:
|
||||
results.error("failed to run reference/driver components")
|
||||
|
||||
IgnoreEntry = typing.Union[str, typing.Pattern]
|
||||
|
||||
def name_matches_pattern(name: str, str_or_re: IgnoreEntry) -> bool:
|
||||
"""Check if name matches a pattern, that may be a string or regex.
|
||||
- If the pattern is a string, name must be equal to match.
|
||||
- If the pattern is a regex, name must fully match.
|
||||
"""
|
||||
# The CI's python is too old for re.Pattern
|
||||
#if isinstance(str_or_re, re.Pattern):
|
||||
if not isinstance(str_or_re, str):
|
||||
return str_or_re.fullmatch(name) is not None
|
||||
else:
|
||||
return str_or_re == name
|
||||
|
||||
def read_outcome_file(outcome_file: str) -> Outcomes:
|
||||
"""Parse an outcome file and return an outcome collection.
|
||||
"""
|
||||
outcomes = {}
|
||||
with open(outcome_file, 'r', encoding='utf-8') as input_file:
|
||||
for line in input_file:
|
||||
(_platform, component, suite, case, result, _cause) = line.split(';')
|
||||
# Note that `component` is not unique. If a test case passes on Linux
|
||||
# and fails on FreeBSD, it'll end up in both the successes set and
|
||||
# the failures set.
|
||||
suite_case = ';'.join([suite, case])
|
||||
if component not in outcomes:
|
||||
outcomes[component] = ComponentOutcomes(set(), set())
|
||||
if result == 'PASS':
|
||||
outcomes[component].successes.add(suite_case)
|
||||
elif result == 'FAIL':
|
||||
outcomes[component].failures.add(suite_case)
|
||||
|
||||
return outcomes
|
||||
|
||||
|
||||
class Task:
|
||||
"""Base class for outcome analysis tasks."""
|
||||
|
||||
# Override the following in child classes.
|
||||
# Map test suite names (with the test_suite_prefix) to a list of ignored
|
||||
# test cases. Each element in the list can be either a string or a regex;
|
||||
# see the `name_matches_pattern` function.
|
||||
IGNORED_TESTS = {} #type: typing.Dict[str, typing.List[IgnoreEntry]]
|
||||
|
||||
def __init__(self, options) -> None:
|
||||
"""Pass command line options to the tasks.
|
||||
|
||||
Each task decides which command line options it cares about.
|
||||
"""
|
||||
pass
|
||||
|
||||
def section_name(self) -> str:
|
||||
"""The section name to use in results."""
|
||||
raise NotImplementedError
|
||||
|
||||
def ignored_tests(self, test_suite: str) -> typing.Iterator[IgnoreEntry]:
|
||||
"""Generate the ignore list for the specified test suite."""
|
||||
if test_suite in self.IGNORED_TESTS:
|
||||
yield from self.IGNORED_TESTS[test_suite]
|
||||
pos = test_suite.find('.')
|
||||
if pos != -1:
|
||||
base_test_suite = test_suite[:pos]
|
||||
if base_test_suite in self.IGNORED_TESTS:
|
||||
yield from self.IGNORED_TESTS[base_test_suite]
|
||||
|
||||
def is_test_case_ignored(self, test_suite: str, test_string: str) -> bool:
|
||||
"""Check if the specified test case is ignored."""
|
||||
for str_or_re in self.ignored_tests(test_suite):
|
||||
if name_matches_pattern(test_string, str_or_re):
|
||||
return True
|
||||
return False
|
||||
|
||||
def run(self, results: Results, outcomes: Outcomes):
|
||||
"""Run the analysis on the specified outcomes.
|
||||
|
||||
Signal errors via the results objects
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class CoverageTask(Task):
|
||||
"""Analyze test coverage."""
|
||||
|
||||
# Test cases whose suite and description are matched by an entry in
|
||||
# IGNORED_TESTS are expected to be never executed.
|
||||
# All other test cases are expected to be executed at least once.
|
||||
|
||||
def __init__(self, options) -> None:
|
||||
super().__init__(options)
|
||||
self.full_coverage = options.full_coverage #type: bool
|
||||
|
||||
@staticmethod
|
||||
def section_name() -> str:
|
||||
return "Analyze coverage"
|
||||
|
||||
def run(self, results: Results, outcomes: Outcomes) -> None:
|
||||
"""Check that all available test cases are executed at least once."""
|
||||
# Make sure that the generated data files are present (and up-to-date).
|
||||
# This allows analyze_outcomes.py to run correctly on a fresh Git
|
||||
# checkout.
|
||||
cp = subprocess.run(['make', 'generated_files'],
|
||||
cwd='tests',
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
check=False)
|
||||
if cp.returncode != 0:
|
||||
sys.stderr.write(cp.stdout.decode('utf-8'))
|
||||
results.error("Failed \"make generated_files\" in tests. "
|
||||
"Coverage analysis may be incorrect.")
|
||||
available = collect_test_cases.collect_available_test_cases()
|
||||
for suite_case in available:
|
||||
hit = any(suite_case in comp_outcomes.successes or
|
||||
suite_case in comp_outcomes.failures
|
||||
for comp_outcomes in outcomes.values())
|
||||
(test_suite, test_description) = suite_case.split(';')
|
||||
ignored = self.is_test_case_ignored(test_suite, test_description)
|
||||
|
||||
if not hit and not ignored:
|
||||
if self.full_coverage:
|
||||
results.error('Test case not executed: {}', suite_case)
|
||||
else:
|
||||
results.warning('Test case not executed: {}', suite_case)
|
||||
elif hit and ignored:
|
||||
# If a test case is no longer always skipped, we should remove
|
||||
# it from the ignore list.
|
||||
if self.full_coverage:
|
||||
results.error('Test case was executed but marked as ignored for coverage: {}',
|
||||
suite_case)
|
||||
else:
|
||||
results.warning('Test case was executed but marked as ignored for coverage: {}',
|
||||
suite_case)
|
||||
|
||||
|
||||
class DriverVSReference(Task):
|
||||
"""Compare outcomes from testing with and without a driver.
|
||||
|
||||
There are 2 options to use analyze_driver_vs_reference_xxx locally:
|
||||
1. Run tests and then analysis:
|
||||
- tests/scripts/all.sh --outcome-file "$PWD/out.csv" <component_ref> <component_driver>
|
||||
- tests/scripts/analyze_outcomes.py out.csv analyze_driver_vs_reference_xxx
|
||||
2. Let this script run both automatically:
|
||||
- tests/scripts/analyze_outcomes.py out.csv analyze_driver_vs_reference_xxx
|
||||
"""
|
||||
|
||||
# Override the following in child classes.
|
||||
# Configuration name (all.sh component) used as the reference.
|
||||
REFERENCE = ''
|
||||
# Configuration name (all.sh component) used as the driver.
|
||||
DRIVER = ''
|
||||
# Ignored test suites (without the test_suite_ prefix).
|
||||
IGNORED_SUITES = [] #type: typing.List[str]
|
||||
|
||||
def __init__(self, options) -> None:
|
||||
super().__init__(options)
|
||||
self.ignored_suites = frozenset('test_suite_' + x
|
||||
for x in self.IGNORED_SUITES)
|
||||
|
||||
def section_name(self) -> str:
|
||||
return f"Analyze driver {self.DRIVER} vs reference {self.REFERENCE}"
|
||||
|
||||
def run(self, results: Results, outcomes: Outcomes) -> None:
|
||||
"""Check that all tests passing in the driver component are also
|
||||
passing in the corresponding reference component.
|
||||
Skip:
|
||||
- full test suites provided in ignored_suites list
|
||||
- only some specific test inside a test suite, for which the corresponding
|
||||
output string is provided
|
||||
"""
|
||||
ref_outcomes = outcomes.get("component_" + self.REFERENCE)
|
||||
driver_outcomes = outcomes.get("component_" + self.DRIVER)
|
||||
|
||||
if ref_outcomes is None or driver_outcomes is None:
|
||||
results.error("required components are missing: bad outcome file?")
|
||||
return
|
||||
|
||||
if not ref_outcomes.successes:
|
||||
results.error("no passing test in reference component: bad outcome file?")
|
||||
return
|
||||
|
||||
for suite_case in ref_outcomes.successes:
|
||||
# suite_case is like "test_suite_foo.bar;Description of test case"
|
||||
(full_test_suite, test_string) = suite_case.split(';')
|
||||
test_suite = full_test_suite.split('.')[0] # retrieve main part of test suite name
|
||||
|
||||
# Immediately skip fully-ignored test suites
|
||||
if test_suite in self.ignored_suites or \
|
||||
full_test_suite in self.ignored_suites:
|
||||
continue
|
||||
|
||||
# For ignored test cases inside test suites, just remember and:
|
||||
# don't issue an error if they're skipped with drivers,
|
||||
# but issue an error if they're not (means we have a bad entry).
|
||||
ignored = self.is_test_case_ignored(full_test_suite, test_string)
|
||||
|
||||
if not ignored and not suite_case in driver_outcomes.successes:
|
||||
results.error("SKIP/FAIL -> PASS: {}", suite_case)
|
||||
if ignored and suite_case in driver_outcomes.successes:
|
||||
results.error("uselessly ignored: {}", suite_case)
|
||||
|
||||
|
||||
def main(known_tasks: typing.Dict[str, typing.Type[Task]]) -> None:
|
||||
main_results = Results()
|
||||
|
||||
try:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('outcomes', metavar='OUTCOMES.CSV',
|
||||
help='Outcome file to analyze')
|
||||
parser.add_argument('specified_tasks', default='all', nargs='?',
|
||||
help='Analysis to be done. By default, run all tasks. '
|
||||
'With one or more TASK, run only those. '
|
||||
'TASK can be the name of a single task or '
|
||||
'comma/space-separated list of tasks. ')
|
||||
parser.add_argument('--list', action='store_true',
|
||||
help='List all available tasks and exit.')
|
||||
parser.add_argument('--require-full-coverage', action='store_true',
|
||||
dest='full_coverage', help="Require all available "
|
||||
"test cases to be executed and issue an error "
|
||||
"otherwise. This flag is ignored if 'task' is "
|
||||
"neither 'all' nor 'analyze_coverage'")
|
||||
options = parser.parse_args()
|
||||
|
||||
if options.list:
|
||||
for task_name in known_tasks:
|
||||
print(task_name)
|
||||
sys.exit(0)
|
||||
|
||||
if options.specified_tasks == 'all':
|
||||
tasks_list = list(known_tasks.keys())
|
||||
else:
|
||||
tasks_list = re.split(r'[, ]+', options.specified_tasks)
|
||||
for task_name in tasks_list:
|
||||
if task_name not in known_tasks:
|
||||
sys.stderr.write('invalid task: {}\n'.format(task_name))
|
||||
sys.exit(2)
|
||||
|
||||
# If the outcome file exists, parse it once and share the result
|
||||
# among tasks to improve performance.
|
||||
# Otherwise, it will be generated by execute_reference_driver_tests.
|
||||
if not os.path.exists(options.outcomes):
|
||||
if len(tasks_list) > 1:
|
||||
sys.stderr.write("mutiple tasks found, please provide a valid outcomes file.\n")
|
||||
sys.exit(2)
|
||||
|
||||
task_name = tasks_list[0]
|
||||
task_class = known_tasks[task_name]
|
||||
if not issubclass(task_class, DriverVSReference):
|
||||
sys.stderr.write("please provide valid outcomes file for {}.\n".format(task_name))
|
||||
sys.exit(2)
|
||||
# mypy isn't smart enough to know that REFERENCE and DRIVER
|
||||
# are *class* attributes of all classes derived from
|
||||
# DriverVSReference. (It would be smart enough if we had an
|
||||
# instance of task_class, but we can't construct an instance
|
||||
# until we have the outcome data, so at this point we only
|
||||
# have the class.) So we use indirection to access the class
|
||||
# attributes.
|
||||
execute_reference_driver_tests(main_results,
|
||||
getattr(task_class, 'REFERENCE'),
|
||||
getattr(task_class, 'DRIVER'),
|
||||
options.outcomes)
|
||||
|
||||
outcomes = read_outcome_file(options.outcomes)
|
||||
|
||||
for task_name in tasks_list:
|
||||
task_constructor = known_tasks[task_name]
|
||||
task_instance = task_constructor(options)
|
||||
main_results.new_section(task_instance.section_name())
|
||||
task_instance.run(main_results, outcomes)
|
||||
|
||||
main_results.info("Overall results: {} warnings and {} errors",
|
||||
main_results.warning_count, main_results.error_count)
|
||||
|
||||
sys.exit(0 if (main_results.error_count == 0) else 1)
|
||||
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# Print the backtrace and exit explicitly with our chosen status.
|
||||
traceback.print_exc()
|
||||
sys.exit(120)
|
||||
@@ -1,129 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Measure memory usage of a minimal client using a small configuration
|
||||
# Currently hardwired to ccm-psk and suite-b, may be expanded later
|
||||
#
|
||||
# Use different build options for measuring executable size and memory usage,
|
||||
# since for memory we want debug information.
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
set -eu
|
||||
|
||||
CONFIG_H='include/mbedtls/mbedtls_config.h'
|
||||
|
||||
CLIENT='mini_client'
|
||||
|
||||
CFLAGS_EXEC='-fno-asynchronous-unwind-tables -Wl,--gc-section -ffunction-sections -fdata-sections'
|
||||
CFLAGS_MEM=-g3
|
||||
|
||||
if [ -r $CONFIG_H ]; then :; else
|
||||
echo "$CONFIG_H not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -i cmake Makefile >/dev/null; then
|
||||
echo "Not compatible with CMake" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $( uname ) != Linux ]; then
|
||||
echo "Only work on Linux" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git status | grep -F $CONFIG_H >/dev/null 2>&1; then
|
||||
echo "mbedtls_config.h not clean" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# make measurements with one configuration
|
||||
# usage: do_config <name> <unset-list> <server-args>
|
||||
do_config()
|
||||
{
|
||||
NAME=$1
|
||||
UNSET_LIST=$2
|
||||
SERVER_ARGS=$3
|
||||
|
||||
echo ""
|
||||
echo "config-$NAME:"
|
||||
cp configs/config-$NAME.h $CONFIG_H
|
||||
scripts/config.py unset MBEDTLS_SSL_SRV_C
|
||||
|
||||
for FLAG in $UNSET_LIST; do
|
||||
scripts/config.py unset $FLAG
|
||||
done
|
||||
|
||||
grep -F SSL_MAX_CONTENT_LEN $CONFIG_H || echo 'SSL_MAX_CONTENT_LEN=16384'
|
||||
|
||||
printf " Executable size... "
|
||||
|
||||
make clean
|
||||
CFLAGS=$CFLAGS_EXEC make OFLAGS=-Os lib >/dev/null 2>&1
|
||||
cd programs
|
||||
CFLAGS=$CFLAGS_EXEC make OFLAGS=-Os ssl/$CLIENT >/dev/null
|
||||
strip ssl/$CLIENT
|
||||
stat -c '%s' ssl/$CLIENT
|
||||
cd ..
|
||||
|
||||
printf " Peak ram usage... "
|
||||
|
||||
make clean
|
||||
CFLAGS=$CFLAGS_MEM make OFLAGS=-Os lib >/dev/null 2>&1
|
||||
cd programs
|
||||
CFLAGS=$CFLAGS_MEM make OFLAGS=-Os ssl/$CLIENT >/dev/null
|
||||
cd ..
|
||||
|
||||
./ssl_server2 $SERVER_ARGS >/dev/null &
|
||||
SRV_PID=$!
|
||||
sleep 1;
|
||||
|
||||
if valgrind --tool=massif --stacks=yes programs/ssl/$CLIENT >/dev/null 2>&1
|
||||
then
|
||||
FAILED=0
|
||||
else
|
||||
echo "client failed" >&2
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
kill $SRV_PID
|
||||
wait $SRV_PID
|
||||
|
||||
scripts/massif_max.pl massif.out.*
|
||||
mv massif.out.* massif-$NAME.$$
|
||||
}
|
||||
|
||||
# preparation
|
||||
|
||||
CONFIG_BAK=${CONFIG_H}.bak
|
||||
cp $CONFIG_H $CONFIG_BAK
|
||||
|
||||
rm -f massif.out.*
|
||||
|
||||
printf "building server... "
|
||||
|
||||
make clean
|
||||
make lib >/dev/null 2>&1
|
||||
(cd programs && make ssl/ssl_server2) >/dev/null
|
||||
cp programs/ssl/ssl_server2 .
|
||||
|
||||
echo "done"
|
||||
|
||||
# actual measurements
|
||||
|
||||
do_config "ccm-psk-tls1_2" \
|
||||
"" \
|
||||
"psk=000102030405060708090A0B0C0D0E0F"
|
||||
|
||||
do_config "suite-b" \
|
||||
"MBEDTLS_BASE64_C MBEDTLS_PEM_PARSE_C" \
|
||||
""
|
||||
|
||||
# cleanup
|
||||
|
||||
mv $CONFIG_BAK $CONFIG_H
|
||||
make clean
|
||||
rm ssl_server2
|
||||
|
||||
exit $FAILED
|
||||
@@ -1,129 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install all the required Python packages, with the minimum Python version.
|
||||
"""
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import typing
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
import framework_scripts_path # pylint: disable=unused-import
|
||||
from mbedtls_framework import typing_util
|
||||
|
||||
def pylint_doesn_t_notice_that_certain_types_are_used_in_annotations(
|
||||
_list: List[typing.Any],
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class Requirements:
|
||||
"""Collect and massage Python requirements."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.requirements = [] #type: List[str]
|
||||
|
||||
def adjust_requirement(self, req: str) -> str:
|
||||
"""Adjust a requirement to the minimum specified version."""
|
||||
# allow inheritance #pylint: disable=no-self-use
|
||||
# If a requirement specifies a minimum version, impose that version.
|
||||
split_req = req.split(';', 1)
|
||||
split_req[0] = re.sub(r'>=|~=', r'==', split_req[0])
|
||||
return ';'.join(split_req)
|
||||
|
||||
def add_file(self, filename: str) -> None:
|
||||
"""Add requirements from the specified file.
|
||||
|
||||
This method supports a subset of pip's requirement file syntax:
|
||||
* One requirement specifier per line, which is passed to
|
||||
`adjust_requirement`.
|
||||
* Comments (``#`` at the beginning of the line or after whitespace).
|
||||
* ``-r FILENAME`` to include another file.
|
||||
"""
|
||||
for line in open(filename):
|
||||
line = line.strip()
|
||||
line = re.sub(r'(\A|\s+)#.*', r'', line)
|
||||
if not line:
|
||||
continue
|
||||
m = re.match(r'-r\s+', line)
|
||||
if m:
|
||||
nested_file = os.path.join(os.path.dirname(filename),
|
||||
line[m.end(0):])
|
||||
self.add_file(nested_file)
|
||||
continue
|
||||
self.requirements.append(self.adjust_requirement(line))
|
||||
|
||||
def write(self, out: typing_util.Writable) -> None:
|
||||
"""List the gathered requirements."""
|
||||
for req in self.requirements:
|
||||
out.write(req + '\n')
|
||||
|
||||
def install(
|
||||
self,
|
||||
pip_general_options: Optional[List[str]] = None,
|
||||
pip_install_options: Optional[List[str]] = None,
|
||||
) -> None:
|
||||
"""Call pip to install the requirements."""
|
||||
if pip_general_options is None:
|
||||
pip_general_options = []
|
||||
if pip_install_options is None:
|
||||
pip_install_options = []
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# This is more complicated than it needs to be for the sake
|
||||
# of Windows. Use a temporary file rather than the command line
|
||||
# to avoid quoting issues. Use a temporary directory rather
|
||||
# than NamedTemporaryFile because with a NamedTemporaryFile on
|
||||
# Windows, the subprocess can't open the file because this process
|
||||
# has an exclusive lock on it.
|
||||
req_file_name = os.path.join(temp_dir, 'requirements.txt')
|
||||
with open(req_file_name, 'w') as req_file:
|
||||
self.write(req_file)
|
||||
subprocess.check_call([sys.executable, '-m', 'pip'] +
|
||||
pip_general_options +
|
||||
['install'] + pip_install_options +
|
||||
['-r', req_file_name])
|
||||
|
||||
DEFAULT_REQUIREMENTS_FILE = 'ci.requirements.txt'
|
||||
|
||||
def main() -> None:
|
||||
"""Command line entry point."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--no-act', '-n',
|
||||
action='store_true',
|
||||
help="Don't act, just print what will be done")
|
||||
parser.add_argument('--pip-install-option',
|
||||
action='append', dest='pip_install_options',
|
||||
help="Pass this option to pip install")
|
||||
parser.add_argument('--pip-option',
|
||||
action='append', dest='pip_general_options',
|
||||
help="Pass this general option to pip")
|
||||
parser.add_argument('--user',
|
||||
action='append_const', dest='pip_install_options',
|
||||
const='--user',
|
||||
help="Install to the Python user install directory"
|
||||
" (short for --pip-install-option --user)")
|
||||
parser.add_argument('files', nargs='*', metavar='FILE',
|
||||
help="Requirement files"
|
||||
" (default: {} in the script's directory)" \
|
||||
.format(DEFAULT_REQUIREMENTS_FILE))
|
||||
options = parser.parse_args()
|
||||
if not options.files:
|
||||
options.files = [os.path.join(os.path.dirname(__file__),
|
||||
DEFAULT_REQUIREMENTS_FILE)]
|
||||
reqs = Requirements()
|
||||
for filename in options.files:
|
||||
reqs.add_file(filename)
|
||||
reqs.write(sys.stdout)
|
||||
if not options.no_act:
|
||||
reqs.install(pip_general_options=options.pip_general_options,
|
||||
pip_install_options=options.pip_install_options)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,187 +0,0 @@
|
||||
#! /usr/bin/env sh
|
||||
|
||||
# output_env.sh
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
#
|
||||
# Purpose
|
||||
#
|
||||
# To print out all the relevant information about the development environment.
|
||||
#
|
||||
# This includes:
|
||||
# - architecture of the system
|
||||
# - type and version of the operating system
|
||||
# - version of make and cmake
|
||||
# - version of armcc, clang, gcc-arm and gcc compilers
|
||||
# - version of libc, clang, asan and valgrind if installed
|
||||
# - version of gnuTLS and OpenSSL
|
||||
|
||||
print_version()
|
||||
{
|
||||
BIN="$1"
|
||||
shift
|
||||
ARGS="$1"
|
||||
shift
|
||||
VARIANT="$1"
|
||||
shift
|
||||
|
||||
if [ -n "$VARIANT" ]; then
|
||||
VARIANT=" ($VARIANT)"
|
||||
fi
|
||||
|
||||
if ! type "$BIN" > /dev/null 2>&1; then
|
||||
echo " * ${BIN##*/}$VARIANT: Not found."
|
||||
return 0
|
||||
fi
|
||||
|
||||
BIN=`which "$BIN"`
|
||||
VERSION_STR=`$BIN $ARGS 2>&1`
|
||||
|
||||
# Apply all filters
|
||||
while [ $# -gt 0 ]; do
|
||||
FILTER="$1"
|
||||
shift
|
||||
VERSION_STR=`echo "$VERSION_STR" | $FILTER`
|
||||
done
|
||||
|
||||
if [ -z "$VERSION_STR" ]; then
|
||||
VERSION_STR="Version could not be determined."
|
||||
fi
|
||||
|
||||
echo " * ${BIN##*/}$VARIANT: ${BIN} : ${VERSION_STR} "
|
||||
}
|
||||
|
||||
echo "** Platform:"
|
||||
echo
|
||||
|
||||
if [ `uname -s` = "Linux" ]; then
|
||||
echo "Linux variant"
|
||||
lsb_release -d -c
|
||||
else
|
||||
echo "Unknown Unix variant"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
print_version "uname" "-a" ""
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "** Tool Versions:"
|
||||
echo
|
||||
|
||||
print_version "make" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
print_version "cmake" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
if [ "${RUN_ARMCC:-1}" -ne 0 ]; then
|
||||
: "${ARMC5_CC:=armcc}"
|
||||
print_version "$ARMC5_CC" "--vsn" "" "head -n 2"
|
||||
echo
|
||||
|
||||
: "${ARMC6_CC:=armclang}"
|
||||
print_version "$ARMC6_CC" "--vsn" "" "head -n 2"
|
||||
echo
|
||||
fi
|
||||
|
||||
print_version "arm-none-eabi-gcc" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
print_version "gcc" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
if [ -n "${GCC_EARLIEST+set}" ]; then
|
||||
print_version "${GCC_EARLIEST}" "--version" "" "head -n 1"
|
||||
else
|
||||
echo " GCC_EARLIEST : Not configured."
|
||||
fi
|
||||
echo
|
||||
|
||||
if [ -n "${GCC_LATEST+set}" ]; then
|
||||
print_version "${GCC_LATEST}" "--version" "" "head -n 1"
|
||||
else
|
||||
echo " GCC_LATEST : Not configured."
|
||||
fi
|
||||
echo
|
||||
|
||||
print_version "clang" "--version" "" "head -n 2"
|
||||
echo
|
||||
|
||||
if [ -n "${CLANG_EARLIEST+set}" ]; then
|
||||
print_version "${CLANG_EARLIEST}" "--version" "" "head -n 2"
|
||||
else
|
||||
echo " CLANG_EARLIEST : Not configured."
|
||||
fi
|
||||
echo
|
||||
|
||||
if [ -n "${CLANG_LATEST+set}" ]; then
|
||||
print_version "${CLANG_LATEST}" "--version" "" "head -n 2"
|
||||
else
|
||||
echo " CLANG_LATEST : Not configured."
|
||||
fi
|
||||
echo
|
||||
|
||||
print_version "ldd" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
print_version "valgrind" "--version" ""
|
||||
echo
|
||||
|
||||
print_version "gdb" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
print_version "perl" "--version" "" "head -n 2" "grep ."
|
||||
echo
|
||||
|
||||
print_version "python" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
print_version "python3" "--version" "" "head -n 1"
|
||||
echo
|
||||
|
||||
# Find the installed version of Pylint. Installed as a distro package this can
|
||||
# be pylint3 and as a PEP egg, pylint. In test scripts We prefer pylint over
|
||||
# pylint3
|
||||
if type pylint >/dev/null 2>/dev/null; then
|
||||
print_version "pylint" "--version" "" "sed /^.*config/d" "grep pylint"
|
||||
elif type pylint3 >/dev/null 2>/dev/null; then
|
||||
print_version "pylint3" "--version" "" "sed /^.*config/d" "grep pylint"
|
||||
else
|
||||
echo " * pylint or pylint3: Not found."
|
||||
fi
|
||||
echo
|
||||
|
||||
: ${OPENSSL:=openssl}
|
||||
print_version "$OPENSSL" "version" "default"
|
||||
echo
|
||||
|
||||
if [ -n "${OPENSSL_NEXT+set}" ]; then
|
||||
print_version "$OPENSSL_NEXT" "version" "next"
|
||||
else
|
||||
echo " * openssl (next): Not configured."
|
||||
fi
|
||||
echo
|
||||
|
||||
: ${GNUTLS_CLI:=gnutls-cli}
|
||||
print_version "$GNUTLS_CLI" "--version" "default" "head -n 1"
|
||||
echo
|
||||
|
||||
: ${GNUTLS_SERV:=gnutls-serv}
|
||||
print_version "$GNUTLS_SERV" "--version" "default" "head -n 1"
|
||||
echo
|
||||
|
||||
echo " * Installed asan versions:"
|
||||
if type dpkg-query >/dev/null 2>/dev/null; then
|
||||
if ! dpkg-query -f '${Status} ${Package}: ${Version}\n' -W 'libasan*' |
|
||||
awk '$3 == "installed" && $4 !~ /-/ {print $4, $5}' |
|
||||
grep .
|
||||
then
|
||||
echo " No asan versions installed."
|
||||
fi
|
||||
else
|
||||
echo " Unable to determine the asan version without dpkg."
|
||||
fi
|
||||
echo
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
print_usage()
|
||||
{
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTION]...
|
||||
Prepare the source tree for a release.
|
||||
|
||||
Options:
|
||||
-u Prepare for development (undo the release preparation)
|
||||
EOF
|
||||
}
|
||||
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
set -eu
|
||||
|
||||
if [ $# -ne 0 ] && [ "$1" = "--help" ]; then
|
||||
print_usage
|
||||
exit
|
||||
fi
|
||||
|
||||
unrelease= # if non-empty, we're in undo-release mode
|
||||
while getopts u OPTLET; do
|
||||
case $OPTLET in
|
||||
u) unrelease=1;;
|
||||
\?)
|
||||
echo 1>&2 "$0: unknown option: -$OPTLET"
|
||||
echo 1>&2 "Try '$0 --help' for more information."
|
||||
exit 3;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
|
||||
#### .gitignore processing ####
|
||||
|
||||
GITIGNORES=$(find . -name ".gitignore")
|
||||
for GITIGNORE in $GITIGNORES; do
|
||||
if [ -n "$unrelease" ]; then
|
||||
sed -i '/###START_COMMENTED_GENERATED_FILES###/,/###END_COMMENTED_GENERATED_FILES###/s/^#//' $GITIGNORE
|
||||
sed -i 's/###START_COMMENTED_GENERATED_FILES###/###START_GENERATED_FILES###/' $GITIGNORE
|
||||
sed -i 's/###END_COMMENTED_GENERATED_FILES###/###END_GENERATED_FILES###/' $GITIGNORE
|
||||
else
|
||||
sed -i '/###START_GENERATED_FILES###/,/###END_GENERATED_FILES###/s/^/#/' $GITIGNORE
|
||||
sed -i 's/###START_GENERATED_FILES###/###START_COMMENTED_GENERATED_FILES###/' $GITIGNORE
|
||||
sed -i 's/###END_GENERATED_FILES###/###END_COMMENTED_GENERATED_FILES###/' $GITIGNORE
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
|
||||
#### Build scripts ####
|
||||
|
||||
# GEN_FILES defaults on (non-empty) in development, off (empty) in releases
|
||||
if [ -n "$unrelease" ]; then
|
||||
r=' yes'
|
||||
else
|
||||
r=''
|
||||
fi
|
||||
sed -i 's/^\(GEN_FILES[ ?:]*=\)\([^#]*\)/\1'"$r/" Makefile */Makefile
|
||||
|
||||
# GEN_FILES defaults on in development, off in releases
|
||||
if [ -n "$unrelease" ]; then
|
||||
r='ON'
|
||||
else
|
||||
r='OFF'
|
||||
fi
|
||||
sed -i '/[Oo][Ff][Ff] in development/! s/^\( *option *( *GEN_FILES *"[^"]*" *\)\([A-Za-z0-9][A-Za-z0-9]*\)/\1'"$r/" CMakeLists.txt
|
||||
@@ -1 +0,0 @@
|
||||
Mbed TLS
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Temporarily (de)ignore Makefiles generated by CMake to allow easier
|
||||
# git development
|
||||
#
|
||||
# Copyright The Mbed TLS Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
|
||||
IGNORE=""
|
||||
|
||||
# Parse arguments
|
||||
#
|
||||
until [ -z "$1" ]
|
||||
do
|
||||
case "$1" in
|
||||
-u|--undo)
|
||||
IGNORE="0"
|
||||
;;
|
||||
-v|--verbose)
|
||||
# Be verbose
|
||||
VERBOSE="1"
|
||||
;;
|
||||
-h|--help)
|
||||
# print help
|
||||
echo "Usage: $0"
|
||||
echo -e " -h|--help\t\tPrint this help."
|
||||
echo -e " -u|--undo\t\tRemove ignores and continue tracking."
|
||||
echo -e " -v|--verbose\t\tVerbose."
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
# print error
|
||||
echo "Unknown argument: '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "X" = "X$IGNORE" ];
|
||||
then
|
||||
[ $VERBOSE ] && echo "Ignoring Makefiles"
|
||||
git update-index --assume-unchanged Makefile library/Makefile programs/Makefile tests/Makefile
|
||||
else
|
||||
[ $VERBOSE ] && echo "Tracking Makefiles"
|
||||
git update-index --no-assume-unchanged Makefile library/Makefile programs/Makefile tests/Makefile
|
||||
fi
|
||||
@@ -1,20 +0,0 @@
|
||||
@rem Build and test Mbed TLS with Visual Studio using msbuild.
|
||||
@rem Usage: windows_msbuild [RETARGET]
|
||||
@rem RETARGET: version of Visual Studio to emulate
|
||||
@rem https://docs.microsoft.com/en-us/cpp/build/how-to-modify-the-target-framework-and-platform-toolset
|
||||
|
||||
@rem These parameters are hard-coded for now.
|
||||
set "arch=x64" & @rem "x86" or "x64"
|
||||
set "cfg=Release" & @rem "Debug" or "Release"
|
||||
set "vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat"
|
||||
|
||||
if not "%~1"=="" set "retarget=,PlatformToolset=%1"
|
||||
|
||||
@rem If the %USERPROFILE%\Source directory exists, then running
|
||||
@rem vcvarsall.bat will silently change the directory to that directory.
|
||||
@rem Setting the VSCMD_START_DIR environment variable causes it to change
|
||||
@rem to that directory instead.
|
||||
set "VSCMD_START_DIR=%~dp0\..\visualc\VS2017"
|
||||
|
||||
"%vcvarsall%" x64 && ^
|
||||
msbuild /t:Rebuild /p:Configuration=%cfg%%retarget% /m mbedTLS.sln
|
||||
Reference in New Issue
Block a user