diff --git a/.ci/aptPackagesToInstall.txt b/.ci/aptPackagesToInstall.txt new file mode 100644 index 0000000..e69de29 diff --git a/.ci/pythonPackagesToInstallFromGit.txt b/.ci/pythonPackagesToInstallFromGit.txt new file mode 100644 index 0000000..e69de29 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c9162b9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +insert_final_newline = true +end_of_line = lf + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 diff --git a/.github/.templateMarker b/.github/.templateMarker new file mode 100644 index 0000000..5e3a3e0 --- /dev/null +++ b/.github/.templateMarker @@ -0,0 +1 @@ +KOLANICH/python_project_boilerplate.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..89ff339 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + allow: + - dependency-type: "all" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..7fe33b3 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,15 @@ +name: CI +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - name: typical python workflow + uses: KOLANICH-GHActions/typical-python-workflow@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71fb1b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +__pycache__ +*.py[co] +/*.egg-info +*.srctrlbm +*.srctrldb +build +dist +.eggs +monkeytype.sqlite3 +/.ipynb_checkpoints diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..67a1858 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,51 @@ +image: registry.gitlab.com/kolanich-subgroups/docker-images/fixed_python:latest + +variables: + DOCKER_DRIVER: overlay2 + SAST_ANALYZER_IMAGE_TAG: latest + SAST_DISABLE_DIND: "true" + SAST_CONFIDENCE_LEVEL: 5 + CODECLIMATE_VERSION: latest + +include: + - template: SAST.gitlab-ci.yml + - template: Code-Quality.gitlab-ci.yml + - template: License-Management.gitlab-ci.yml + +build: + tags: + - shared + - linux + stage: build + variables: + GIT_DEPTH: "1" + PYTHONUSERBASE: ${CI_PROJECT_DIR}/python_user_packages + + before_script: + - export PATH="$PATH:$PYTHONUSERBASE/bin" # don't move into `variables` + - apt-get update + # todo: + #- apt-get -y install + #- pip3 install --upgrade + #- python3 ./fix_python_modules_paths.py + + script: + - python3 -m build -nw bdist_wheel + - mv ./dist/*.whl ./dist/securesystemslib_KOLANICH-0.CI-py3-none-any.whl + - pip3 install --upgrade ./dist/*.whl + - coverage run --source=securesystemslib_KOLANICH -m --branch pytest --junitxml=./rspec.xml ./tests/test.py + - coverage report -m + - coverage xml + + coverage: "/^TOTAL(?:\\s+\\d+){4}\\s+(\\d+%).+/" + + cache: + paths: + - $PYTHONUSERBASE + + artifacts: + paths: + - dist + reports: + junit: ./rspec.xml + cobertura: ./coverage.xml diff --git a/Code_Of_Conduct.md b/Code_Of_Conduct.md new file mode 100644 index 0000000..bcaa2bf --- /dev/null +++ b/Code_Of_Conduct.md @@ -0,0 +1 @@ +No codes of conduct! \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5779168 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Santiago Torres + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..20f0fa8 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +include UNLICENSE +include *.md +include tests +include .editorconfig diff --git a/ReadMe.md b/ReadMe.md new file mode 100644 index 0000000..f8419da --- /dev/null +++ b/ReadMe.md @@ -0,0 +1,17 @@ +securesystemslib_KOLANICH.py +============================ +~~[wheel (GitLab)](https://gitlab.com/KOLANICH-libs/securesystemslib_KOLANICH.py/-/jobs/artifacts/master/raw/dist/securesystemslib_KOLANICH-0.CI-py3-none-any.whl?job=build)~~ +[wheel (GHA via `nightly.link`)](https://nightly.link/KOLANICH-libs/securesystemslib_KOLANICH.py/workflows/CI/master/securesystemslib_KOLANICH-0.CI-py3-none-any.whl) +~~![GitLab Build Status](https://gitlab.com/KOLANICH-libs/securesystemslib_KOLANICH.py/badges/master/pipeline.svg)~~ +~~![GitLab Coverage](https://gitlab.com/KOLANICH-libs/securesystemslib_KOLANICH.py/badges/master/coverage.svg)~~ +[![GitHub Actions](https://github.com/KOLANICH-libs/securesystemslib_KOLANICH.py/workflows/CI/badge.svg)](https://github.com/KOLANICH-libs/securesystemslib_KOLANICH.py/actions/) +[![Libraries.io Status](https://img.shields.io/librariesio/github/KOLANICH-libs/securesystemslib_KOLANICH.py.svg)](https://libraries.io/github/KOLANICH-libs/securesystemslib_KOLANICH.py) +[![Code style: antiflash](https://img.shields.io/badge/code%20style-antiflash-FFF.svg)](https://github.com/KOLANICH-tools/antiflash.py) + +My additions to [`securesystemslib`](https://github.com/secure-systems-lab/securesystemslib). + +* https://github.com/secure-systems-lab/securesystemslib/pull/452 - implements a method to generate a `securesystemslib` `dict` for a `ed25519` key - used internally. +* https://github.com/secure-systems-lab/securesystemslib/pull/451 - implements import of SSH keys. `from securesystemslib_KOLANICH.convert.ssh import import_ssh_key` +* https://github.com/secure-systems-lab/securesystemslib/pull/453 - monkey-patches inconsistent keyids for ECDSA keys - just `import securesystemslib_KOLANICH` + +The most of this lib is licensed under `Unlicense`, but some files with portions copied from `securesystemslib` are licensed under `MIT`. diff --git a/UNLICENSE b/UNLICENSE new file mode 100644 index 0000000..efb9808 --- /dev/null +++ b/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8947d97 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,39 @@ +[build-system] +requires = ["setuptools>=61.2.0", "setuptools_scm[toml]>=3.4.3"] +build-backend = "setuptools.build_meta" + +[project] +name = "securesystemslib_KOLANICH" +readme = "ReadMe.md" +description = "A temporary workaround for non-merging my PRs into `securesystemslib`" +authors = [{name = "KOLANICH"}] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Other Environment", + "Intended Audience :: Developers", + "License :: Public Domain", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Software Development :: Libraries :: Python Modules", +] +keywords = ["securesystemslib_KOLANICH"] +license = {text = "MIT AND Unlicense"} +requires-python = ">=3.4" +dynamic = ["version"] +dependencies = [ + "securesystemslib", + "cryptography", +] + +[project.urls] +Homepage = "https://github.com/KOLANICH-libs/securesystemslib_KOLANICH.py" + +[tool.setuptools] +zip-safe = true + +[tool.setuptools.packages.find] +include = ["securesystemslib_KOLANICH", "securesystemslib_KOLANICH.*"] + +[tool.setuptools_scm] diff --git a/securesystemslib_KOLANICH/__init__.py b/securesystemslib_KOLANICH/__init__.py new file mode 100644 index 0000000..9864a21 --- /dev/null +++ b/securesystemslib_KOLANICH/__init__.py @@ -0,0 +1 @@ +__license__ = "Unlicense" diff --git a/securesystemslib_KOLANICH/convert/__init__.py b/securesystemslib_KOLANICH/convert/__init__.py new file mode 100644 index 0000000..9864a21 --- /dev/null +++ b/securesystemslib_KOLANICH/convert/__init__.py @@ -0,0 +1 @@ +__license__ = "Unlicense" diff --git a/securesystemslib_KOLANICH/convert/hazmat.py b/securesystemslib_KOLANICH/convert/hazmat.py new file mode 100644 index 0000000..6695e4e --- /dev/null +++ b/securesystemslib_KOLANICH/convert/hazmat.py @@ -0,0 +1,133 @@ +""" +This module contains functions to convert `cryptography.hazmat` keys into `securesystemlib` key dicts. +""" + + +import typing + +from cryptography.hazmat.backends.openssl.ec import _EllipticCurvePrivateKey, _EllipticCurvePublicKey +from cryptography.hazmat.backends.openssl.ed25519 import _Ed25519PrivateKey, _Ed25519PublicKey +from cryptography.hazmat.backends.openssl.rsa import _RSAPrivateKey, _RSAPublicKey +from cryptography.hazmat.primitives.serialization import Encoding, NoEncryption, PrivateFormat, PublicFormat +from securesystemslib.keys import import_ecdsakey_from_pem, import_rsakey_from_pem + +from ..keys import format_ed25519_dict + + +__license__ = "Unlicense" + + +def _hazmat_key_to_pem( + key: typing.Union[ + _RSAPrivateKey, + _EllipticCurvePrivateKey, + ] +) -> str: + """The approach already used in this lib is to convert keys into PEM and then to parse from it.""" + + if key.__class__.__name__.endswith("PrivateKey"): + serialized = key.private_bytes( + Encoding.PEM, + PrivateFormat.TraditionalOpenSSL, + NoEncryption(), + ) + elif key.__class__.__name__.endswith("PublicKey"): + serialized = key.public_bytes( + Encoding.PEM, + PublicFormat.SubjectPublicKeyInfo, + ) + else: + raise TypeError(key) + + return serialized.decode("utf-8") + + +def _import_hazmat_ed25519_private_key( + key: _Ed25519PrivateKey, +) -> dict: + """Imports hazmat ed25519 private key""" + + pub = key.public_key().public_bytes( + Encoding.Raw, + PublicFormat.Raw, + ) + sec = key.private_bytes( + Encoding.Raw, + PrivateFormat.Raw, + NoEncryption(), + ) + return format_ed25519_dict( + pub, + sec, + ) + + +def _import_hazmat_ed25519_public_key( + key: _Ed25519PublicKey, +) -> dict: + """Imports hazmat ed25519 public key""" + + pub = key.public_bytes( + Encoding.Raw, + PublicFormat.Raw, + ) + return format_ed25519_dict( + pub, + None, + ) + + +def _import_rsa_key( + key: _RSAPrivateKey, +) -> dict: + """Imports hazmat RSA key""" + + return import_rsakey_from_pem(_hazmat_key_to_pem(key)) + + +def _import_ecdsa_key( + key: _EllipticCurvePrivateKey, +) -> dict: + """Imports hazmat ECDSA key""" + + return import_ecdsakey_from_pem(_hazmat_key_to_pem(key)) + + +_typeMapping = { + _Ed25519PrivateKey: _import_hazmat_ed25519_private_key, + _Ed25519PublicKey: _import_hazmat_ed25519_public_key, + _RSAPrivateKey: _import_rsa_key, + _RSAPublicKey: _import_rsa_key, + _EllipticCurvePrivateKey: _import_ecdsa_key, + _EllipticCurvePublicKey: _import_ecdsa_key, +} + + +def import_hazmat_key(key: typing.Union[_RSAPrivateKey, _EllipticCurvePrivateKey, _Ed25519PrivateKey]) -> dict: + """ + + Converts a `cryptography.hazmat` key into a dictionary conformant to 'securesystemslib.formats.KEY_SCHEMA'. + + + key: + A key of the classes from `cryptography.hazmat` module. Currently only keys of `openssl` backend are implemented. + + + securesystemslib.exceptions.FormatError, if 'key_value' does not conform to + 'securesystemslib.formats.KEYVAL_SCHEMA', or if the private key is not + present in 'key_value' if requested by the caller via 'private'. + NotImplementedError, if we cannot convert a key of this type. + + + None. + + + A 'securesystemslib.formats.KEY_SCHEMA' dictionary.""" + + key_type = type(key) + try: + mapper = _typeMapping[key_type] + except KeyError as ex: + raise NotImplementedError(key_type) from ex + else: + return mapper(key) diff --git a/securesystemslib_KOLANICH/convert/ssh.py b/securesystemslib_KOLANICH/convert/ssh.py new file mode 100644 index 0000000..951e5ac --- /dev/null +++ b/securesystemslib_KOLANICH/convert/ssh.py @@ -0,0 +1,47 @@ +""" +This module contains functions to import OpenSSH keys. +""" + +import re +import typing + +from cryptography.hazmat.primitives.serialization.ssh import load_ssh_private_key, load_ssh_public_key + +from .hazmat import import_hazmat_key + +__license__ = "Unlicense" + +openssh_text_format_marker_re = re.compile(b"^-{2,}BEGIN OPENSSH PRIVATE KEY-{2,}$") + + +def import_ssh_key(key: typing.Union[str, bytes], password: typing.Optional[bytes] = None): + """ + + Imports either a public or a private key in OpenSSH format + + + key: + A string in OpenSSH format, usually Base64-encoded. + + + securesystemslib.exceptions.FormatError, if the arguments are improperly + formatted. + + securesystemslib.exceptions.UnsupportedAlgorithmError, if 'pem' specifies + an unsupported key type. + + + None. + + + A dictionary containing the keys, conforming to 'securesystemslib.formats.KEY_SCHEMA'. + """ + + if isinstance(key, str): + key = key.encode("utf-8") + + first_line = key.split(b"\n", 1)[0] + if openssh_text_format_marker_re.match(first_line): + return import_hazmat_key(load_ssh_private_key(key, password)) + + return import_hazmat_key(load_ssh_public_key(key)) diff --git a/securesystemslib_KOLANICH/keys.py b/securesystemslib_KOLANICH/keys.py new file mode 100644 index 0000000..4d1ac67 --- /dev/null +++ b/securesystemslib_KOLANICH/keys.py @@ -0,0 +1,64 @@ +import binascii + +from securesystemslib import formats, settings +from securesystemslib.keys import _get_keyid + + +__license__ = "MIT" + + +def format_ed25519_dict(public: bytes, private: bytes, scheme="ed25519"): + """ + + Formats a ed25519 private key dict. + + + public: + Bytes of public key. + + private: + Bytes of private key. + + scheme: + The signature scheme used by the generated Ed25519 key. + + + None. + + + None. + + + A dictionary containing the ED25519 keys and other identifying information. + Conforms to 'securesystemslib.formats.ED25519KEY_SCHEMA'. + """ + + assert private is None or len(private) == 32 # nosec assert_used + assert len(public) == 32 # nosec assert_used + + # Are the arguments properly formatted? If not, raise an + # 'securesystemslib.exceptions.FormatError' exceptions. + formats.ED25519_SIG_SCHEMA.check_match(scheme) + + # Begin building the Ed25519 key dictionary. + ed25519_key = {} + keytype = "ed25519" + + # Generate the keyid of the Ed25519 key. 'key_value' corresponds to the + # 'keyval' entry of the 'Ed25519KEY_SCHEMA' dictionary. The private key + # information is not included in the generation of the 'keyid' identifier. + key_value = {"public": binascii.hexlify(public).decode(), "private": ""} + keyid = _get_keyid(keytype, scheme, key_value) + + if private is not None: + # Build the 'ed25519_key' dictionary. Update 'key_value' with the Ed25519 + # private key prior to adding 'key_value' to 'ed25519_key'. + key_value["private"] = binascii.hexlify(private).decode() + + ed25519_key["keytype"] = keytype + ed25519_key["scheme"] = scheme + ed25519_key["keyid"] = keyid + ed25519_key["keyid_hash_algorithms"] = settings.HASH_ALGORITHMS + ed25519_key["keyval"] = key_value + + return ed25519_key diff --git a/tests/data/ssh/ecdsa b/tests/data/ssh/ecdsa new file mode 100644 index 0000000..5ca9f76 --- /dev/null +++ b/tests/data/ssh/ecdsa @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQRIz8F5gDezWgzdlRn5Upj7B1NoK43R +wP1d/oiCtNKSYDdql9ds3d+5zzEhnhWvdjGOn1sKwAFlbkz+aueExAkvAAAAqGkmJORpJi +TkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEjPwXmAN7NaDN2V +GflSmPsHU2grjdHA/V3+iIK00pJgN2qX12zd37nPMSGeFa92MY6fWwrAAWVuTP5q54TECS +8AAAAhAMfqco7t7Cdz3rXsPcUwOINw4CKTqyTpOCFTzjULEB6AAAAACWVjZHNhIGtleQEC +AwQFBg== +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/data/ssh/ecdsa.pub b/tests/data/ssh/ecdsa.pub new file mode 100644 index 0000000..c154e3e --- /dev/null +++ b/tests/data/ssh/ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEjPwXmAN7NaDN2VGflSmPsHU2grjdHA/V3+iIK00pJgN2qX12zd37nPMSGeFa92MY6fWwrAAWVuTP5q54TECS8= ecdsa key diff --git a/tests/data/ssh/ed25519 b/tests/data/ssh/ed25519 new file mode 100644 index 0000000..42367f7 --- /dev/null +++ b/tests/data/ssh/ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAUMmZQY7F/6Pvhj+LQn6HLke1TI0L1qvVImeBCxKjFuAAAAJAh8wZwIfMG +cAAAAAtzc2gtZWQyNTUxOQAAACAUMmZQY7F/6Pvhj+LQn6HLke1TI0L1qvVImeBCxKjFuA +AAAED6uVRyKJZMvslMIFpm4nbqMcRlzza7VwJobiRcbLNwSBQyZlBjsX/o++GP4tCfocuR +7VMjQvWq9UiZ4ELEqMW4AAAAC2VkMjU1MTkga2V5AQI= +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/data/ssh/ed25519.pub b/tests/data/ssh/ed25519.pub new file mode 100644 index 0000000..b9a878d --- /dev/null +++ b/tests/data/ssh/ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBQyZlBjsX/o++GP4tCfocuR7VMjQvWq9UiZ4ELEqMW4 ed25519 key diff --git a/tests/data/ssh/generate.sh b/tests/data/ssh/generate.sh new file mode 100755 index 0000000..4988329 --- /dev/null +++ b/tests/data/ssh/generate.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +types="ecdsa ed25519 rsa" # dsa + +for t in $types; do + yes | ssh-keygen -t $t -C "$t key" -N "" -f ./$t; +done diff --git a/tests/data/ssh/rsa b/tests/data/ssh/rsa new file mode 100644 index 0000000..a523263 --- /dev/null +++ b/tests/data/ssh/rsa @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +fyozEzAWaCa90AAAAHcnNhIGtleQECAwQ= +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/data/ssh/rsa.pub b/tests/data/ssh/rsa.pub new file mode 100644 index 0000000..b260788 --- /dev/null +++ b/tests/data/ssh/rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzzjkzJGZjENWuFFpjhhK7y+YpMMST18lCK28dlG3QbqbpVJggC+3DcpD4GfFVHTEUpJWplatF4nlpHrzQTc/8RhJzVg+FY3hZXRdxX5J5zJ5vW1aTQdduj0AGMQ0RRaFQo3o5fGMQdrthDUW1/9ybGF0sv4DlTH0rtR8yCvXpl0LmaCIn0MireG8SqsaxdYDb8KdbOHL8Ezo2UmqZg0+svwkphEFoFzqQYVNAhgG4+/5Yotl2PBxZrSUWEUApqvWSS5BeyT/cTnf/8XDGV64H2Qmw9nZhRTIan6GgTgzPOhaX3yUxXS4ZI5rnWRQJuOk/J6FVKsJFNVA+/BAsxjcbUpms+PUtrXe+mHMLcb9FvQAiR9oteNMWUM3X1H8hVRZ20ETTzZVXM44mbSJ+ZvBEcpsGo9RmaMnvsc+4QI9ak/wEojPGN1msNXh/R8RWnhG+sCkbM9Btf2wf1RUyxtpkpYksbcDVyQEl+Rr6x2M+sJH9KZCzS9OFL8hZHKsCAks= rsa key diff --git a/tests/tests.py b/tests/tests.py new file mode 100644 index 0000000..e90b8e2 --- /dev/null +++ b/tests/tests.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +""" + +test_openssh.py + + +KOLANICH + + +Oct 31, 2022 + + +See LICENSE for licensing information. + + +Test OpenSSH-related functions. + +""" + +import itertools +import re +import sys +import unittest +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from collections import OrderedDict + +dict = OrderedDict + +import unittest +from pathlib import Path + +from securesystemslib.keys import create_signature, verify_signature + +import securesystemslib_KOLANICH +from securesystemslib_KOLANICH import * +from securesystemslib_KOLANICH.convert.ssh import import_ssh_key + +this_dir = Path(__file__).resolve().absolute().parent +keys_dir = this_dir / "data" / "ssh" + + +__license__ = "Unlicense" + +# pylint: disable=wrong-import-position + +TEST_DATA = b"test" + + +class TestOpenSSH(unittest.TestCase): + def test_openssh_import_and_sign_and_verify(self): + files = sorted(set(keys_dir.glob("*.pub"))) + for pub_f in files: + sec_f = pub_f.parent / pub_f.stem + with self.subTest(pub_f=pub_f, sec_f=sec_f): + pub = import_ssh_key(pub_f.read_text(), None) + sec = import_ssh_key(sec_f.read_text(), None) + signature = create_signature(sec, TEST_DATA) + self.assertTrue(verify_signature(pub, signature, TEST_DATA)) + + +if __name__ == "__main__": + unittest.main()