Initial commit

Initial commit.
This commit is contained in:
kntran1
2026-03-23 14:40:39 -05:00
parent e84b2b4166
commit 4e2a5258a5
872 changed files with 165227 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pytest
# List of tests expected to fail for some reason
XFAILED_TESTS = {
"tests/test_keys.py::test_getpriv[openssl-ed25519]",
"tests/test_keys.py::test_getpriv[openssl-x25519]",
"tests/test_keys.py::test_getpriv[pkcs8-rsa-2048]",
"tests/test_keys.py::test_getpriv[pkcs8-rsa-3072]",
"tests/test_keys.py::test_getpriv[pkcs8-ed25519]",
"tests/test_keys.py::test_getpub[pem-ed25519]",
"tests/test_keys.py::test_sign_verify[x25519]",
}
def pytest_runtest_setup(item):
if item.nodeid in XFAILED_TESTS:
pytest.xfail()

View File

@@ -0,0 +1,112 @@
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pytest
from click.testing import CliRunner
from imgtool.main import imgtool
from imgtool import imgtool_version
# all available imgtool commands
COMMANDS = [
"create",
"dumpinfo",
"getpriv",
"getpub",
"getpubhash",
"keygen",
"sign",
"verify",
"version",
]
def test_new_command():
"""Check that no new commands had been added,
so that tests would be updated in such case"""
for cmd in imgtool.commands:
assert cmd in COMMANDS
def test_help():
"""Simple test for the imgtool's help option,
mostly just to see that it can be started"""
runner = CliRunner()
result_short = runner.invoke(imgtool, ["-h"])
assert result_short.exit_code == 0
result_long = runner.invoke(imgtool, ["--help"])
assert result_long.exit_code == 0
assert result_short.output == result_long.output
# by default help should be also produced
result_empty = runner.invoke(imgtool)
assert result_empty.exit_code == 0
assert result_empty.output == result_short.output
def test_version():
"""Check that some version info is produced"""
runner = CliRunner()
result = runner.invoke(imgtool, ["version"])
assert result.exit_code == 0
assert result.output == imgtool_version + "\n"
result_help = runner.invoke(imgtool, ["version", "-h"])
assert result_help.exit_code == 0
assert result_help.output != result.output
def test_unknown():
"""Check that unknown command will be handled"""
runner = CliRunner()
result = runner.invoke(imgtool, ["unknown"])
assert result.exit_code != 0
@pytest.mark.parametrize("command", COMMANDS)
def test_cmd_help(command):
"""Check that all commands have some help"""
runner = CliRunner()
result_short = runner.invoke(imgtool, [command, "-h"])
assert result_short.exit_code == 0
result_long = runner.invoke(imgtool, [command, "--help"])
assert result_long.exit_code == 0
assert result_short.output == result_long.output
@pytest.mark.parametrize("command1", COMMANDS)
@pytest.mark.parametrize("command2", COMMANDS)
def test_cmd_dif_help(command1, command2):
"""Check that all commands have some different help"""
runner = CliRunner()
result_general = runner.invoke(imgtool, "--help")
assert result_general.exit_code == 0
result_cmd1 = runner.invoke(imgtool, [command1, "--help"])
assert result_cmd1.exit_code == 0
assert result_cmd1.output != result_general.output
if command1 != command2:
result_cmd2 = runner.invoke(imgtool, [command2, "--help"])
assert result_cmd2.exit_code == 0
assert result_cmd1.output != result_cmd2.output

View File

@@ -0,0 +1,253 @@
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pytest
import subprocess
from click.testing import CliRunner
from imgtool import main as imgtool_main
from imgtool.main import imgtool
# all supported key types for 'keygen'
KEY_TYPES = [*imgtool_main.keygens]
KEY_ENCODINGS = [*imgtool_main.valid_encodings]
PUB_HASH_ENCODINGS = [*imgtool_main.valid_hash_encodings]
PVT_KEY_FORMATS = [*imgtool_main.valid_formats]
OPENSSL_KEY_TYPES = {
"rsa-2048": "Private-Key: (2048 bit, 2 primes)",
"rsa-3072": "Private-Key: (3072 bit, 2 primes)",
"ecdsa-p256": "Private-Key: (256 bit)",
"ecdsa-p384": "Private-Key: (384 bit)",
"ed25519": "ED25519 Private-Key:",
"x25519": "X25519 Private-Key:",
}
GEN_KEY_EXT = ".key"
GEN_ANOTHER_KEY_EXT = ".another.key"
PUB_KEY_EXT = ".pub"
PUB_KEY_HASH_EXT = ".pubhash"
def tmp_name(tmp_path, key_type, suffix=""):
return tmp_path / (key_type + suffix)
@pytest.fixture(scope="session")
def tmp_path_persistent(tmp_path_factory):
return tmp_path_factory.mktemp("keys")
@pytest.mark.parametrize("key_type", KEY_TYPES)
def test_keygen(key_type, tmp_path_persistent):
"""Generate keys by imgtool"""
runner = CliRunner()
gen_key = tmp_name(tmp_path_persistent, key_type, GEN_KEY_EXT)
assert not gen_key.exists()
result = runner.invoke(
imgtool, ["keygen", "--key", str(gen_key), "--type", key_type]
)
assert result.exit_code == 0
assert gen_key.exists()
assert gen_key.stat().st_size > 0
# another key
gen_key2 = tmp_name(tmp_path_persistent, key_type, GEN_ANOTHER_KEY_EXT)
assert str(gen_key2) != str(gen_key)
assert not gen_key2.exists()
result = runner.invoke(
imgtool, ["keygen", "--key", str(gen_key2), "--type", key_type]
)
assert result.exit_code == 0
assert gen_key2.exists()
assert gen_key2.stat().st_size > 0
# content must be different
assert gen_key.read_bytes() != gen_key2.read_bytes()
@pytest.mark.parametrize("key_type", KEY_TYPES)
def test_keygen_type(key_type, tmp_path_persistent):
"""Check generated keys"""
assert key_type in OPENSSL_KEY_TYPES
gen_key = tmp_name(tmp_path_persistent, key_type, GEN_KEY_EXT)
result = subprocess.run(
["openssl", "pkey", "-in", str(gen_key), "-check", "-noout", "-text"],
capture_output=True,
text=True,
)
assert result.returncode == 0
assert "Key is valid" in result.stdout
assert OPENSSL_KEY_TYPES[key_type] in result.stdout
@pytest.mark.parametrize("key_type", KEY_TYPES)
@pytest.mark.parametrize("format", PVT_KEY_FORMATS)
def test_getpriv(key_type, format, tmp_path_persistent):
"""Get private key"""
runner = CliRunner()
gen_key = tmp_name(tmp_path_persistent, key_type, GEN_KEY_EXT)
result = runner.invoke(
imgtool,
[
"getpriv",
"--key",
str(gen_key),
"--format",
format,
],
)
assert result.exit_code == 0
@pytest.mark.parametrize("key_type", KEY_TYPES)
@pytest.mark.parametrize("encoding", KEY_ENCODINGS)
def test_getpub(key_type, encoding, tmp_path_persistent):
"""Get public key"""
runner = CliRunner()
gen_key = tmp_name(tmp_path_persistent, key_type, GEN_KEY_EXT)
pub_key = tmp_name(tmp_path_persistent, key_type, PUB_KEY_EXT
+ "." + encoding)
assert not pub_key.exists()
result = runner.invoke(
imgtool,
[
"getpub",
"--key",
str(gen_key),
"--output",
str(pub_key),
"--encoding",
encoding,
],
)
assert result.exit_code == 0
assert pub_key.exists()
assert pub_key.stat().st_size > 0
@pytest.mark.parametrize("key_type", KEY_TYPES)
@pytest.mark.parametrize("encoding", PUB_HASH_ENCODINGS)
def test_getpubhash(key_type, encoding, tmp_path_persistent):
"""Get the hash of the public key"""
runner = CliRunner()
gen_key = tmp_name(tmp_path_persistent, key_type, GEN_KEY_EXT)
pub_key_hash = tmp_name(
tmp_path_persistent, key_type, PUB_KEY_HASH_EXT + "." + encoding
)
assert not pub_key_hash.exists()
result = runner.invoke(
imgtool,
[
"getpubhash",
"--key",
str(gen_key),
"--output",
str(pub_key_hash),
"--encoding",
encoding,
],
)
assert result.exit_code == 0
assert pub_key_hash.exists()
assert pub_key_hash.stat().st_size > 0
@pytest.mark.parametrize("key_type", KEY_TYPES)
def test_sign_verify(key_type, tmp_path_persistent):
"""Test basic sign and verify"""
runner = CliRunner()
gen_key = tmp_name(tmp_path_persistent, key_type, GEN_KEY_EXT)
wrong_key = tmp_name(tmp_path_persistent, key_type, GEN_ANOTHER_KEY_EXT)
image = tmp_name(tmp_path_persistent, "image", "bin")
image_signed = tmp_name(tmp_path_persistent, "image", "signed")
with image.open("wb") as f:
f.write(b"\x00" * 1024)
# not all required arguments are provided
result = runner.invoke(
imgtool,
[
"sign",
"--key",
str(gen_key),
str(image),
str(image_signed),
],
)
assert result.exit_code != 0
assert not image_signed.exists()
result = runner.invoke(
imgtool,
[
"sign",
"--key",
str(gen_key),
"--align",
"16",
"--version",
"1.0.0",
"--header-size",
"0x400",
"--slot-size",
"0x10000",
"--pad-header",
str(image),
str(image_signed),
],
)
assert result.exit_code == 0
assert image_signed.exists()
assert image_signed.stat().st_size > 0
# original key can be used to verify a signed image
result = runner.invoke(
imgtool,
[
"verify",
"--key",
str(gen_key),
str(image_signed),
],
)
assert result.exit_code == 0
# 'another' key is not valid to verify a signed image
result = runner.invoke(
imgtool,
[
"verify",
"--key",
str(wrong_key),
str(image_signed),
],
)
assert result.exit_code != 0
image_signed.unlink()