123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- #!/usr/bin/env python3
- # pylint: disable=import-outside-toplevel
- """Test key management commands."""
- import os
- from testlib import check, util
- from testlib.log import log
- from testlib.feature import Feature
- from testlib.proc import Tinc
- from testlib.test import Test
- def init(ctx: Test) -> Tinc:
- """Initialize a node."""
- node = ctx.node()
- stdin = f"""
- init {node}
- set Port 0
- set Address localhost
- set DeviceType dummy
- """
- node.cmd(stdin=stdin)
- return node
- TEST_DATA = b"foo bar baz"
- def try_rsa_keys(priv_path: str, pub_path: str) -> None:
- """Check that RSA key pair works."""
- try:
- import cryptography # type: ignore
- from cryptography.hazmat.primitives import hashes, serialization # type: ignore
- from cryptography.hazmat.primitives.asymmetric import padding # type: ignore
- except ImportError:
- log.info("cryptography module missing or broken, skipping key checks")
- return
- version = cryptography.__version__.split(".", maxsplit=2)
- if not (int(version[0]) >= 3 and int(version[1]) >= 3):
- log.info("cryptography module is too old, skipping key check")
- return
- log.info("loading keys from (%s, %s)", priv_path, pub_path)
- with open(priv_path, "rb") as priv, open(pub_path, "rb") as pub:
- key_pair = (
- serialization.load_pem_private_key(priv.read(), password=None),
- serialization.load_pem_public_key(pub.read()),
- )
- s_pad = padding.PSS(
- mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH
- )
- s_hash = hashes.SHA256()
- log.info("signing sample data %s", TEST_DATA)
- signature = key_pair[0].sign(TEST_DATA, s_pad, s_hash)
- log.info("verifying signature %s", signature)
- key_pair[1].verify(signature, TEST_DATA, s_pad, s_hash)
- def test_rsa(foo: Tinc) -> None:
- """Test command 'generate-rsa-keys'."""
- for key_size in "foobar", "512", "16384":
- log.info("generate %s-bit RSA key", key_size)
- _, err = foo.cmd("generate-rsa-keys", key_size, code=1)
- check.is_in("Invalid key size", err)
- log.info("generate RSA key with too many arguments")
- _, err = foo.cmd("generate-rsa-keys", "2048", "4096", code=1)
- check.is_in("Too many arguments", err)
- rsa_priv = foo.sub("rsa_key.priv")
- rsa_pub = foo.sub(f"hosts/{foo}")
- for key_size in "1024", "1025":
- log.info("generate %s-bit RSA key", key_size)
- _, err = foo.cmd("generate-rsa-keys", key_size)
- check.is_in("Generating 1024 bits", err)
- check.is_in("generating a weak", err)
- check.is_in("found and disabled", err)
- try_rsa_keys(rsa_priv, rsa_pub)
- for key_size in "2048", "2049":
- log.info("generate %s-bit RSA key", key_size)
- os.remove(rsa_priv)
- _, err = foo.cmd("generate-rsa-keys", key_size)
- check.is_in("Generating 2048 bits", err)
- check.file_exists(rsa_priv)
- try_rsa_keys(rsa_priv, rsa_pub)
- log.info("check that key is present")
- key = util.read_text(rsa_priv)
- check.has_prefix(key, "-----BEGIN RSA PRIVATE KEY-----")
- if os.name != "nt":
- log.info("remove access to private key")
- os.chmod(rsa_priv, 0)
- _, err = foo.cmd("generate-rsa-keys", "1024", code=1)
- check.is_in("Error opening file", err)
- def test_rsa_nolegacy(foo: Tinc) -> None:
- """Test command 'generate-rsa-keys' on a nolegacy build."""
- log.info("generate RSA key with nolegacy tinc")
- _, err = foo.cmd("generate-rsa-keys", code=1)
- check.is_in("Unknown command", err)
- def test_eddsa(foo: Tinc) -> None:
- """Test command 'generate-ed25519-keys'."""
- log.info("generate EC key with too many arguments")
- _, err = foo.cmd("generate-ed25519-keys", "2048", code=1)
- check.is_in("Too many arguments", err)
- log.info("generate and replace EC key")
- _, err = foo.cmd("generate-ed25519-keys")
- check.is_in("found and disabled", err)
- log.info("remove EC key files")
- ec_priv = foo.sub("ed25519_key.priv")
- ec_pub = foo.sub(f"hosts/{foo}")
- os.remove(ec_priv)
- os.remove(ec_pub)
- log.info("create new EC key files")
- foo.cmd("generate-ed25519-keys")
- check.has_prefix(util.read_text(ec_priv), "-----BEGIN ED25519 PRIVATE KEY-----")
- check.has_prefix(util.read_text(ec_pub), "Ed25519PublicKey")
- if os.name != "nt":
- log.info("remove access to EC private key file")
- os.chmod(ec_priv, 0)
- _, err = foo.cmd("generate-ed25519-keys", code=1)
- check.is_in("Error opening file", err)
- def run_tests(foo: Tinc) -> None:
- """Run tests."""
- test_eddsa(foo)
- if Feature.LEGACY_PROTOCOL in foo.features:
- test_rsa(foo)
- else:
- test_rsa_nolegacy(foo)
- with Test("run tests") as context:
- run_tests(init(context))
|