From 6e55c86ef9e9cff1a2f09213d3fb3b3da9cf1810 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 30 Jun 2026 11:50:52 +0200 Subject: [PATCH 1/3] Test ML-DSA keytypes Added ML-DSA: This will require newer securesystemslib Current test_keytype_and_scheme is preserved for the "standard" ketytypes (the ones referenced in the spec). This way new more optional keytypes will be ergonomic to xfail when needed. We could set the "non-standard" keytypes to xpass (so failures would be listed but would not fail a run) but that seems more complex: Users already have two fine options: * add new failing tests to the clients xfails list "test_mldsa_keytype_and_scheme" will cover all mldsa tests * postpone conformance upgrade until suppport is added The 9000 char signature line is obnoxious but I don't want to replace it with "00"*4627 since it's possible this would not be a valid ASN1.DER key -- we can move the sigs to a resource file if the long lines are an issue. Signed-off-by: Jussi Kukkonen --- clients/go-tuf/go-tuf.xfails | 2 + .../_internal/repository_simulator.py | 9 ++ tuf_conformance/conftest.py | 4 +- tuf_conformance/test_keys.py | 94 ++++++++++++++----- 4 files changed, 84 insertions(+), 25 deletions(-) diff --git a/clients/go-tuf/go-tuf.xfails b/clients/go-tuf/go-tuf.xfails index 5bb8a0d..d863bcf 100644 --- a/clients/go-tuf/go-tuf.xfails +++ b/clients/go-tuf/go-tuf.xfails @@ -2,3 +2,5 @@ # Example: (commented out since the XFAIL is not needed with current go-tuf) # test_keytype_and_scheme[rsa/rsassa-pss-sha256] + +test_mldsa_keytype_and_scheme diff --git a/tuf_conformance/_internal/repository_simulator.py b/tuf_conformance/_internal/repository_simulator.py index 096eada..1729972 100644 --- a/tuf_conformance/_internal/repository_simulator.py +++ b/tuf_conformance/_internal/repository_simulator.py @@ -74,6 +74,15 @@ ("ed25519", "ed25519"): [ CryptoSigner.generate_ed25519() for _ in range(NUM_SIGNERS) ], + ("ml-dsa", "ml-dsa-44/1"): [ + CryptoSigner.generate_mldsa(scheme="ml-dsa-44/1") for _ in range(NUM_SIGNERS) + ], + ("ml-dsa", "ml-dsa-65/1"): [ + CryptoSigner.generate_mldsa(scheme="ml-dsa-65/1") for _ in range(NUM_SIGNERS) + ], + ("ml-dsa", "ml-dsa-87/1"): [ + CryptoSigner.generate_mldsa(scheme="ml-dsa-87/1") for _ in range(NUM_SIGNERS) + ], } diff --git a/tuf_conformance/conftest.py b/tuf_conformance/conftest.py index 6bfe8ac..94cb0fc 100644 --- a/tuf_conformance/conftest.py +++ b/tuf_conformance/conftest.py @@ -98,9 +98,7 @@ def read_xfails(pytestconfig: pytest.Config) -> list[str]: @pytest.fixture(autouse=True) -def conformance_xfail( - pytestconfig: pytest.Config, request: pytest.FixtureRequest -) -> None: +def conformance_(pytestconfig: pytest.Config, request: pytest.FixtureRequest) -> None: xfails = read_xfails(pytestconfig) if request.node.originalname in xfails or request.node.name in xfails: diff --git a/tuf_conformance/test_keys.py b/tuf_conformance/test_keys.py index ceea2ea..ac1fafe 100644 --- a/tuf_conformance/test_keys.py +++ b/tuf_conformance/test_keys.py @@ -1,6 +1,7 @@ import json import pytest +from securesystemslib.signer import KEY_FOR_TYPE_AND_SCHEME, SSlibKey from tuf.api.metadata import Metadata, Root, Snapshot, Targets, Timestamp from tuf_conformance._internal.client_runner import ClientRunner @@ -141,6 +142,36 @@ def test_duplicate_sig_keyids(client: ClientRunner, server: SimulatorServer) -> assert client.version(Snapshot.type) is None +def _test_keytype_and_scheme_internal( + client: ClientRunner, + server: SimulatorServer, + keytype: str, + scheme: str, + bad_sig: str, +) -> None: + init_data, repo = server.new_test(client.test_name) + assert client.init_client(init_data) == 0 + # Add a new root signer with given keytype. + # Increase root threshold so the new key is required + signer = repo.new_signer(keytype, scheme) + repo.add_key(Root.type, signer=signer) + repo.root.roles[Root.type].threshold += 1 + repo.publish([Root.type]) + + assert client.refresh(init_data) == 0 + assert client.version(Root.type) == 2 + + # Create new root version. Replace the correct signature with one that looks + # reasonable for the keytype but is incorrect. Expect client to refuse the new root. + repo.publish([Root.type]) + root_md = Metadata.from_bytes(repo.signed_mds[Root.type].pop()) + root_md.signatures[signer.public_key.keyid].signature = bad_sig + repo.signed_mds[Root.type].append(root_md.to_bytes()) + + assert client.refresh(init_data) == 1 + assert client.version(Root.type) == 2 + + # keytype, scheme and an example signature from this type of key standard_keytypes = [ ( @@ -159,11 +190,10 @@ def test_duplicate_sig_keyids(client: ClientRunner, server: SimulatorServer) -> "b61589620c287e23a00abf0e653421010a0ad33869e5a096d604e08d7b4f8eb9c58ebb8a02124576be776f86ab5a3b05dbb6f27cc47f4b144f32ba4012d4b302", ), ] - -ids = [f"{keytype}/{scheme}" for keytype, scheme, _ in standard_keytypes] +standard_params = [pytest.param(*k, id=f"{k[0]}/{k[1]}") for k in standard_keytypes] -@pytest.mark.parametrize("keytype, scheme, bad_sig", standard_keytypes, ids=ids) +@pytest.mark.parametrize("keytype, scheme, bad_sig", standard_params) def test_keytype_and_scheme( client: ClientRunner, server: SimulatorServer, @@ -172,27 +202,47 @@ def test_keytype_and_scheme( bad_sig: str, ) -> None: """Test that client supports keytypes referenced in the TUF specification""" - init_data, repo = server.new_test(client.test_name) - assert client.init_client(init_data) == 0 - # Add a new root signer with given keytype. - # Increase root threshold so the new key is required - signer = repo.new_signer(keytype, scheme) - repo.add_key(Root.type, signer=signer) - repo.root.roles[Root.type].threshold += 1 - repo.publish([Root.type]) - - assert client.refresh(init_data) == 0 - assert client.version(Root.type) == 2 + _test_keytype_and_scheme_internal(client, server, keytype, scheme, bad_sig) + + +# ML-DSA is not yet enabled by default in securesystemslib: enable for the test +KEY_FOR_TYPE_AND_SCHEME.update( + { + ("ml-dsa", "ml-dsa-44/1"): SSlibKey, + ("ml-dsa", "ml-dsa-65/1"): SSlibKey, + ("ml-dsa", "ml-dsa-87/1"): SSlibKey, + } +) +mldsa_keytypes = [ + ( + "ml-dsa", + "ml-dsa-44/1", + "2589e6a4807acd47d240ada0a4dfb1a12832a9fb8c79ca38fe8911c50f491bdfd9f262635066e53d5ac09a923d636d0fb7815f0a5467aff2c1e0ca1cb25c276ac4aa56b20673d0855a98f0477941055a750ca13f71d51f0f5e85d532f1368544cf7cdb1515a2e686cb4f36adfdbab82b07f2b47541f99004cc21f104d2becc90f2a93333556963523cd271731a719276f30c0c96aa110bc8d6f7fd052cd954f62bd868ec351a8651c0520c3aa9e5b724b8eb7d0f06f640da3229f4ac8e732d2712ceeee6fb91ff56637ba82a840712453827306fffe13415f0d87f25756fe1738e7a2300b58f7dbd1706449049ed771f80a13c47c112530a6a9e938796b200e14adcc2dc5541197ff0ada4b2db62e18b5538674ea274fb7cc938341326bf8b456dc398ddd0516d5e4fd5d864318e015c02a9d460f19d998990fef8088f418af897d3fab16f598dbcde66d797de45b056c98d6b9e9e2b38bf7187d4ef4c59d4064cbbb7c58e2cca9721c048b2c4f9399788b98b2c50cb593e23fb51234ca88bbb644b7f9103c7d9da567902afa05420d5c0372104b3cfe176115dd84b9d47720ee39cfbf3817b9aabb470d3bc6379913c3f72d34dfa4977110c84eb67ca7589e0e7c9bcb145084f82e1b723fb596575d7b41f7728ca9614fd9ebdc737374131f0c3e6c843bbfd1007196c1a789815a3182b465a1da9ebad5afdc3310c0285e422c561894f0a56d62c58b526f5ac79f76b5b2a197053f0d4929ad3a33a57cf2db8d5080f1caf54ed3776942ad5f780f3a241dc32c1529e6306710db9f34fe80f0b61619b04547e68878a2bc7baf873789ec3c31aa34b8d901355e1b628f2e867abb3e5f52ee3386f7a385c8627b2f913ebbd804a396a5b26ef9e5ae87a16345fd39b435106d2f4d28f00b4551354b8c377cc4c2ac10305a4fbf5a2bb4437532f64e8877fdad8765497ca352bca3f3bc793d8df90b92dc4c183cc2f8cddb06347be895121006cc21ae9b995d574219ff29f8208052c2bf52ae224b434a1b372e26d9493bf3642d6bddfd4ad078add3f5385b19a16b411ab7cd09c1ce348e5f4997ae68219868e5ce1a62cdd0919de07796f8ccefc68b681f402cf16d0d14463fccbff387078c9165f21efde75d96492fc23300c555c9998d81a3540a4cceee9337314bf9083b5839c6a620b18ee0426466699c407c9585e99cc4c1e5c0168a655da6ebdf565e0f6a770cf945f6e02caac319fbc46b971d55689dccb50daf28b6d96c4f5cefab27073332257e567227d0ca643d48d8a8ea3f84e7397dc3c667d0f24c3ca895089ea6aaf0eaccec375f3d44091018c7ad7d41c47392eb92e071c5bc5e63da13c1205f556854bfe506cb40447b087022058a1dce71a7fa3502f13d02b46abf5e516576164be7a1b8b090eea324fe39b870c7aea9f5e5fb3d9c1dc08a3e46e73e14d25882f1a4d62cebe0521211dbb0e42a435a77d445954b286f43e72eb12f258ff786652a80f9202379069cd76d3dc05cd616f8f2acf85eb213ded8775e8fabf5d8d8dd46e06408cc6d4f26046eb5c9a6933a902324a937479e5865170e2bfadc76ea09244f645341c02ef02c9eb431ccf573af274f9ac95ca847594bface51f4160b1a65e9b9533bdc86ae9a162f5763064c46359835c2f31613e7fa1b1b39599f014a840de712cc00eb1844aea666fca9fd53675b3d1c7efbf56afa21f3fdecce9d81c2cd9a573e6fa1db83a024ca8086ff12392e1665aa34bcb491ddd114cf072dea870899881c636721ddc6a4b9b4ec8699f429ce96364655b59b70da4b419790329cdd6835e8fbcd562a25ad28e7362abb086ca6d5db3007bbf111ea25a718a84f25ca45b2b2d6c79e62f558f1412cd8810e2774506756977811d88a54f3494e901eab7cc4082a1dc503ed40434b009c713cf43bbe0c281af853587f6e82ac8cd0d946bf857f349803659589904e3f41d0127daf9d42ca58e6d67fab40779bc3ffc1e9f6e8f15ea382be80528e9a005830145ced767d41b91f8dc76b8020fe2ca9923cd16775ca51afd2f40a39cc624bd47b6f3f491f17289247e58ffb406c089cad3b812da1f5dafdcee48ed5429dd67582cd4b6f4e1f43e7bad01123ad58fe52e76c62c1116a08517616cbff8630d908e26ff9d973f91a0ec7e7c6d50082e9fdd40f2cd24674379f3d551c070671318832b9d9aa5c69e6c15f36b2fd93dabf3428bdd8d445afc6ed9853ecc8d2b850eb32a5b8650db89599434523af992648ccd51ee871f981b9b92da2810d5c9a33f3f3689752cea3ff574a3766d3c8092cabf3dff3363e4a4a8a94224715b2fe5cea5bb59469746be0ee04fbdc0cd83d22742cdf28720f7951f8637c5972a3d445e868c3d0256d7acf5c53fe27bae15ae3371c09f71c845b85571e5e137cf249a567b58aad4a6ffcf942e68818103d5301dccb37e337ab3c5fa51fbb2ad39aa32ced8142c491501e045628b4b66a1314c2ec1fda3d1edc7b3cfacd525802fde7da443fc712709fab614457b82e31da60a285b4052ab13d77f783ccde999691513467834ed69f976ecff98361d9a49a82222e1bcd5af4f5014d83567c4ae9ecde260fdd953c5cc85c46d7c91084c36eb05a672e2b8d857135b921be50b8aec3101990c105ae20d28158b9ebec0b51694b9740b1a96efae3d7ba67932e1402a9553a24ee3197f162774f6e8c30ff0702181057e8270028978aac97513e8f7959d223d7514ffa1ddad96eab25f12558ec8d19bb912f7201a6e1bafe869b33c34556b19d80e267a98134a2ba82ccc65c45d2d5d811fd8b0e49359193530b2099ff88b3abf6ae72158c725df1d1cf4f3c13a334e314bb055e937bf7738cb7023827b60ce72de9e86749f49de93fd26747eae63805c3196ad3ead35460feae6614a8dd27c706de6b175493e44db1102300a0d3b4191e545cb384d6c62eaeabed785e50465208831584d7f1cb4aabb8f19231d9ddbd3a9fe1d43dcb25c6de42d45ec974fc65c773cfe4ff30c0c246e25d785a3c37ab3c268d44482190fbeca657f868fffef5dbef01ea67ea76b74b48bc3ae7a95a481a1436996b75b897a1c46bac68b411f16fe9639515498f5f9aca26d404b81d293b2c21fc813e6c9a289fac72a9cad0feabc9182b82638641409e290d57e46de015030284d3444324612cf5a4a8c95a300cf5a0297cd1f03e01cf4dfc7fce5be30bd0a18ba7116d6ca9f0563a1087a1a9c9753ca9f8caf5b8644adc8b7abe338e30a788c1d92464cbd85b65b2373c48ce7ef3fef4f97fa431b0a32383e444c6879868ebef4f6001a1e4f52939ba1a6afb9bad0d2dde3fd1c4b5f6ca5a9b3cbcecfdedfe2f1191c26282d303b444652637584858cbabfe2ef00000000000000000000000000000000000d1e2c3f", + ), + ( + "ml-dsa", + "ml-dsa-65/1", + "d1a19edbdb8dea28d2a930e7f9c2425f7e4a025330a544565e1c9945735db5bf101cfa4ff67f7a3c160eb6bf2aaa74860c7c08158a86cd6ce537ec51013c57544f7a3a8a7b522e3a1a288dca90306a88622d62be3ec928bef85ec46e0370ea88c3477294802bc22931c4986444f5612eab8737aba1a8903a090c59d541f54c02a752dbb127f5d30876bf67a1ebb8b8cd6b990fe9c47784327b6659f96796315e8c34c97a2b1b5f3045e1bbe4dcc031f051116827d6c2dbe074156ca58fa1314e04b337f28d13c33ba3edb4040bbe0bdd9f17aa5c28f633683e0bbc240bde24bfe537e7157836ac6de34cfdbe8bc6ef9483271b9f2d10404d67e94fbaa58aebce0f2ddd76bbe18889eead3fa2b543fb6c30cc235cc56fb07cfb0ea29101fd074d726a24ef56eac26d81a0e7c955c612d432c20d240a3e01ac04832f2b50622d1b7062f7547ecf91b0cfef48ec42a610e528eca25aa0dbd6aaa3b3ebd84431b96af0660616c7f69ef43a7a4a8d4d19c241fefb9e5aa0c9ca0009fe01eb74993ef2e887d822ffec09cdedbde0f0b179ad969ed435f902243c4e32432a0ea5767975160d89a9c1940179e3d55bcb3c81ab38d53e8a935c9081d28b245cae8d280477acf1cfc70fffa5cae38b17709fc5d0fe27673436f596a71660077a2d86379e114803c6471430668b54096b15dead9cdb91b2c285a9ca7de6614ba661aa711cfb121f36ab187b3ff69a25fb77db7627f6983f70c2114c01a78cbb76649f94253a1ec39e17814d74b1af1ce28287ad86232de4594badf128cc070cffef72d13a730f795712359ca3233ef7ae6b2e43a609921fe3c750c45f732907b47d4f095f07ed2b1b097d0a2d8ed925ef61dadcd994bda7f6aec415092354c44c50b9028b326589d01fd2012fae15851b48dc32a4c2afbe05111db82398a798457facded8880b5b0092a3ccbb1bf414c1e83393fdefbe034c1ee5203337ad7451229238e6ab6486ff88738ab521b10a248bf7db800bbef7f7919d58a127548558e92af8586bf147b8c239887a94d448d646243010866505cd64118d6a2fb11b5c770368c36164a77cff04b6984b1e3c49e02e1550641ba3e518fbf552f9c0dde8b5f568e579d9c7fdde2658c5ea1f5d86ee34af9a750e76f486624338b3e2f3cab9fc35a87e3ea202d1053280967e069b0590a2250af0014d94fa6a8ae5b4d02ee2540f31576a1003c38bcae21d6b545fb99452f9358ad39604847af00dc66e025013dd08e68acca2b63188881fac7bd7ce9c6d65b74602825ea37c02d5ccaae1f586aedd806fc48930b66b17d6431b4111133c314e8d4c7ad65c7a38f4ef7c863ab3df85479f7609d86e23ca36775a5c53597230b3e4c654f7ad257ba6528917d6b327a8e8a071dc0e5e81049834f6a53e1622ce1037ae877ec380e7fe7f9951089b7cf42386483e7488e3d09c70beaf27810696643d4d8a4ba0dd9e86bd60bee2d40ded73caa106c62e5b2f116a1d74ef4203f32fd09a54a4230e41a80df5c7ea7f17ac0744ece524f040718b1f3a2f79863a905520dde8885597b02e6ea1b97b1637a0a52a936758951677036010ed3ccfb2802c7776bc196a8c820e57caa0aa8c83700865ccaac7363b947c4cf5a56e75494e59cbb1437b13c393fc661d52d0fcd0c5d0f5c74041037e4ab9d0ec11835ea95c6155a3dac44ac30d45fee4d0ad0ef776f4701f54a62ec427530d24b7d1799b48fd41048b5a4c3b4d1a9d34c8b6a993774ab6aad3b3313533cea1c767654ff996c870b80e8b74554fec839e13f1f6261ae2de1c8d69a0d80f9f343138c49a46202bd3727c04acc9efffb3343bdab46acf20ff3013f16a4b0ea7a2844edb8ac610ff12c8ea5092d06e75a244c66312c8b3734fca9b42c934adcfd160656f7851783ab7a49274d359201a5fcf219faaed34b1d589a86095ae2bfec989c0a813213f8270739c5a6c3d34d2973cc3eb2547daef1a0dbbc6fc43138e6cd20a8c2fcf0ff99981a1c0b26a12d092a071648603b0f47f257789e4907f2abb943e035821cdf81bc3debdb9502b808f3b9774b9aca311dd0bd66afa071c3375cb032493b382e4ab015e026f2c53547e39da9fd4793378a7bc80a63a4bbf32d5985487e42af9b33068bd81e3a0c1cbb05d72d021da730833d6d0c783359ca06a9f06b2220864c45b76ab16e09c382f2784d34b280bd86b77644e5b8e179e2495f9123e97a12c09435fd9f0967eb48dfdc22878874a59beb176c537876731c4e0c281d7c83de295542231e49db642001bf68088027b9f59a313f93f6cdcb6bdb585297b90eefaa84583563fe56d3330ea136c7abff760c9b267abca417ac22b71d84e1377b5e05b9e81b562f4c5dc438335e236d002433a22e77e6256b1aacf0ae76399adf802c25d5b58cb07b8dd911bebe6731b642e462c4f7d93bbddb167f1475d3000e8f593a4f16da7b07ca47ac6cd20b1c13f714cba4f8bbbd5699cb7d69997ca8249c42de07615f6a1b52478a83f586e24c5f77d403d5278736a8d4500e6bc5c4643382f8bc43fc8eaa81ed66a41b77acb0176cb99e49c8a4717006a0a0fbf081e4bc4fdb5b3cbfe79971ac8f70b36608ba16853ad59dbe13996beaf0fb02cd08f7e1fbd00e5506cb3399cad5cc6fa50a9647a70d897cfd94081a7c1e04e33bd56f96bcc1e88375c8121399cacaebc2b7986dea96fd7915b97bfe0428dbf7f1fb7f032fdffc4fb9489abefd6c9d42edc7ea89c3755c38e13a2fb1883edb16ee3c5a1c3674c1cead4db42f5182389142e52582c069e6546a4088d654e0d4d4a1b4d12e7731d251ac8458ba12b92b6ec80bf4bf146d4760765200026bf9ba7836e730774f27e5157532c24cb49ffcf24202c8d2c4bb77ce03a0894be62dab17aba0a0d8e6ea4c331f924d5f5cc67e15fda08ffa3fca7d99a5e3788e1fa2c37817207d8eef3c9e90b89a6da1abb1e97d3e0e27e4e6074731e3b66be0dee69cbafae85b4ccd7631f9af991fa64702a8f0fb889ce429f85d88f46d9e265e199c2193240e1ce6247e15abd3e1d9c8cf52aef83b4bddf1962ac25d5dd831a5be0184463d1eb2316cfdfe04c5aea173e86bcf0369893bc951bacb42cfde467a265bc507c27f806f803be30e05236675aaecaf782a13a74b8722df9aa6e13b0a359c7f053e7b2a14505a4b70246c4504b765a89be46537ab64737a5c2cdc3426bf9198ab4bdcea8d5817f2b6850a78fc43a2473b21fc0924e04e917287cf54a69a0810f4d215115fb1c2e57aa3efdb04e1c27356375bc1c3b819227fac17bd5d21d2531acca3ff1abe1d2130f72da4a7b4f1fd61c201603a60a3ad8be2e2fc05f473ae3e7f059a2d2d8b1ccbefaadc5beef0291ae9cedb7d6b7309b32ad8a6470c878b1a96d38c0a6b377db26edd4e5346db88c28e8fd5eccc25e137650f14a19b12f3aa81acb94277307ff495906c4d251e072575b64b2d8ce113af897f5f1b30eb2f913226b3b4f424ed3ee5b9f38c6c828a0594694e1a2c16e2c41e1c6ed01c808f2ac57492e08363df3d12c0fdf8e2f77da3be758d930c1bab2f70516ec0dba556166281caf7eca72115dc50376b78091de5cd616f3cfa9080eb6af33cf93979a2fdf66d045eb180039c1564e84326138d036cc6844463edafb1d09a96e8019d6753cb9d7fcb57f31c5fe272d2be99ae60b30b218797e0772c8b376cb83be3348733cfbc9580f87592777a127befe99aa0a0252ba92a710120066d8cb48414dc2d727650b3d19bac50c0b445545121a8556e0cc867543dcd087811f1cb152a3d680dd7f0141a92c8186500dcf092382f99050c48ae5284e23e69518e0d8a6f27aeda61007e307f06ec6a717cb5bb706b7f3e138c3f5a3682220eed645f89382526d8a4a2438c124fcec9a2ea07c0ead337ee5661b144d7e4411140813745692cdaeeeccf636d85d8626e36a94695cfaf45a025e73baaebd57253354bed3b3ef97a491c91ef76962ed7d0f25e722b067401ab93d08b95270a102f7315c027b4056a1fb07a92a3ba33184450c15b0e6a50ff5175596225012efe35d7efd69fddeccd07b3dfefa096c72288be7682a937888907ca86ead99b83f5562598809766607aa1eee7cdfeb8c70b1c2404b30a85e06db0cb453bb39bfb7f603383ca675e14c60b94d59c4d8af4bd3ca5588faa36c966fa8ba5c803df8eadb884efde697799b91a938e2b6c21c202f0e31d845a72c9f43ffe03472fda75b38ca49bfb8be142459ef5ada16c41587e71f6591bec9dacf769ec6ffb094ff996026ae2ee062c23d31cb76b78283515600e52d97bb67736898405cb9781d861f3449895e2a399f3ae81d794fdc23097de795ddae9f91ce9f49f3b1b51ee1e170bc7055c7474f7ab449639fe626e5758570f11e917eeafbe998d0cb6a31e62ac7cf8ac7c2c23bcf4496b53b52313287de06c5e5608114168d43b54084a1926548828311a609f605bbce34a53fecccac3ddb79090dbb6a53d06efc5363ea2e78d32e7e1b8e8b0f6837f82f131b0a08f256a6457159425474da396cb1c8f662700231011f8b15113724d463c25ef62a696f969dd6f32c65787fb3de4a505288a20f3c63737ea2bde43f5f6fa8f3fa7d8592a6cbf9000000000000000000000000000000000000060c11191f25", + ), + ( + "ml-dsa", + "ml-dsa-87/1", + "965711dfc5f8a5e89e2843dfc775634306ea556fdc670c65d7b7f5caaf083f32bc3cf7a8b6435fc6acf05255855f7a5df5a21120d1e990ec12383f71ce00394291b2212cf86d5e0fb18c05e59263285e4fb990051b46cabb146366a32d4b82ccf7a58e9d3ebdd136fb584c21bdd6ff0dcaddb1bf6c21fa110d87e4e7832420abb67f010791fbb7886fd0c465cf83e150fc42f16f5d780d4880f84d0dc4d26e83a90743d17f8f0d8b48018be7aec1767eed833f64445e660740f7b3bb52d0d27d1bf077aaa5c4e0dd2ed1a0813569b8d28f75c249c8f7c250dbcf7de191b964b9522aaae177bc271f551d4ca0f68a511a2cc27248687c7deb9c4c30861cc76b1cd224cd34570b25d1103f3228238a46c6517579a69c682fb267f90dbfe4344df8aa38a981c7d41cde0425ad72d15b9f9882bfe001d7fe69507f8172c7d0cd0c689c66662c710185c0f7f858ed122266c6116418269c2e12e43541a960154e75c93c9171cb60cf171540b2d638c77489efd4a7b4207349138d1d61aac7089e20ae475a5b75fa45d7abdc0e550622d70f304b8b31205a543516ab60c37f0f94c4b6b0fad0e2ca84b87adc5134c38ff25a1ac54494126372c7971c13ea1ebb2a2a92b84dab68931e7ce0602104e074d1dd341c81024b6b4d5450c6acaaac66b4c97ceb20615380c4e586d32226cbd0a7bcb8451b324332e06d4180d39112fedcb71fba85714d429dc37407d1c58cbff474a6185f629e69e10983d3076dc9582da494eeb432a456d4d7c705187f413a35549d2b0372313ac43c830229654f7777a2193b4b389f7a8e4c7fcf38aec6375a42d48f04f010e1dae7a3c1ceb9f4343d81f6b3af753f38d24931a72d4f2ffd02f75d286f7d814d03ae9a346b1e2bc935a0567f7ffb89bee638099421621238c0996506c51449bc6ea4804cd611c338dfc549aa19c2f786c9640906a59eece8ac94ef9014ed937cd149b6ed9b8479cc7c8d5ad90152a4081c19a80196ca81917ed26970ed67009ae982169f8dfa9c6256cb19c46ce519e65e7b5fc12b4c9531a9b830e551bf5c6206c74a631b810475117a7ea48610f2cf486f3f43f474b5ad411d805df0b576c6694c49f3511f5e1edd4f19cff785d1f127482e3413c69be0625db2aecf22209911753c7d52b362177682c777eb76a25b1313fcc1621b9814513b9447c4f453b27d889c4a8c9b4b25dd2fbcbd13bb1040fe0667f5a6c817ec3324f660d756939d70fa0ad18294e45c772e53061632a3d988c30c2f2d9555cc7864cfc06466dc4025e91c7cc744a5c30675187f3e0fc438308e0721101708c8e4aa7109fc57166db6d54677d91b5e69a6c2698474822299bf36abfa173dd5ad0bdde098f3f694632e7ba49e2a0738c52da5a56a17deae1af17723eabe0cad7177fa3a003f80562f60210262dd7df27988429817701c6ae711f8dbea0f71f2f575ea2c2d42c6bdd90a4637f2e55e7514fc73c3237ba4d5b7453eb9767d20dda6260570fcb39b9888365c00acdc2b1e90ce43550f081dbfe333a1e93107a3fdb1762387b4ef2d1c25e89bbef0734e6416eaaef4ca68c151a1c0edfa9260ad1dc10cae7bae56496402cf1093f47a48224e8d2cdd4f8be1fadd5004ee16c00b874be76f0a72312fc60c49ed675798e8f94bef692ff86813662eed9b65b1352848daa868552f4341332000b95dc5767f8ff12397a0d80ab12761c41ef6b79719a80ca1d7b12ced1fd6d0a4d0ed6de41b8449edd101555dd5f157df17784fa5e3d60555fc6f5afff42801452e03b0d9554700c714062a247fa7a57f5a51385bacb00b8b27b32922819568557121c971c1f3ce4a527623d96e702f5a375bed89c6600523f21634b8c8c330558666fc19158380fada7a4eda33cd98c2cf191f2dd161880a657313f7bc026fe6b5f93ff3c945885d16f4eb2a6b7eb15177c99fcfeec8cc7711f3d752edc7c018e771eff27f16aee51f0358736c864de6a1c152df4458c84d777a1f38a4d5fc07e445fb33947cd45d2a6ff9397cf6b2bf428bc4ac9dca1ecce69be069004516652e96d5f86650a9e7b4d660c0d255ecb5f872dc78c32f3722beeef68f6a4b029b26f0f82b6b6908fab48c1563c85a13b630702570ef14198b2002f9384d8cbd04f2e769bd2e9d43b507e75d8a3f40947faff60dfa47d5ff0880cd093b9d5583f8f722f5987718e4f280703b3d1a388c4e5ca4292e7053d0a54526dbf06df03822c35e5b203e87bd0b5c4e550e54826a8a5bd57f9ca1445bbf4617ec89f181be770a921438496f5a920b49e346652f86a91255cb984005755e3641964d4e6c175fd265eb8d29a07f36f05c0100bbe184fa49968ad079bb7cf3a418373b40ce5e6e4c039a6baef0815c3803878acef9d5d56204093db85e304287e7106d49796a1d8e7513d3f09da721deaf98b22f8a67550b8510847d8f53791966230120d15bd0b956f6e01698e3e739c295d640f6a857d28eed826d9217f156773aa8ae9a4adfa16d14517aeeccbeaac346afa2bcc1f88827fd7b30005f7b3c036c8cc34372d1964d8e522407bd4df59e31b949524bca71a5269cbd05814b262ff00edabd00d9a1b60c50d83a6904a4482ba335aa1fb09a3f030e1a391665e8a3846fa2eb90a1aef8d2a563152a46b448c7eaea9af52e1efd4cbd7e478cd337d32f2f769f906c8724b516716187d57b6220df4b4c5d8d3b60df972e3744858d22cc7dd734d41408e3892f79f3fb2f773adbe20fc2572d3b2f734e6132aed792a024effb6b8d7a7b8fef1fcfb4a2c35ef5143bc10c3b8e4270f8b2280bd18fb776ad5f4c1d246f323144b8c756b1000e83e7117b8afb6ab323d32924e38edc6c3de7494447d8baab6759b64ea651f2031d73d2d6e43e0cd8b17da0a99074a62fdcdf7dc2832965155fd98cd145b67d2fb3c5d66d56224736c16efa71aa32661be3ca6d81f275bb2c4a7e08fe72b18d668d317e4d5fc9425e17739591926d8dbaf340ade9e5251bab7d70689071662447cc18d24d47babae6cdc64bae5755bf278af986b8f5fe730d8bdd5bb979d478ff2050aca7d18b6b3a848d233874953dd2a10a5eb186b0f4a7ab6d427bf38fe0667e85a2433cf65a10c0f544e2b8d1e51ba461a4b84e083d48e7c9a78fdc4eeef51e40955947ba7afd23e1fb1da9c9b949ece297237c46b937006a1362f62a39430e7211efc2e74ae636c2ed33e01742468c6e4b4925421cf0824fdf64b71f5bab8606ce3b1ee4c33b31836217105bd79709bcdcf0fedefa4601c5ef9fbc6e0828ae41fb892629c9fe6449c9b0bbe25a207465e3dd59ccfe0328ad430878cfa130f060703b6316d380f42dcc2f2d58c5554fb85cc45ae419f5bca1de433f2f1f23f3a3202f926ac797624256bef899d1fc6794bd941ccb76ffcd5e3051ec1fecfcc99a987080ea12f77c889a44abf2b5b82b338490072d4083d5b4d4a252ceaed92aaaaab1d797a4b8ad99f9dc686109c69675a6be06cd7632e0b7bc90e01f67055c5661b2fa3ab120b0f900ad1f46b518c77fd75814a9a69b1e98c3f44c18d0d7bba93d4152974110013da69b0a38a1050e8590a58756f74d0c1eba543aac9bd51b4e3af3c2bbd76d98a87d2ebf6b544c2e452f002c8a4b6374d6c53e71422f79a42ae1b8b006ba1722f2e4de3a9dae0fa9baa6e1e1b24b90c5534359300e38a547dd2b73fc4e816f9ae2613143192df95ae69a31cf61dfe5bbc57c42cfc082d5683be973a712375dce9e1dc0337dbb14fe88ceb2019846c601586d97737411d50dfd3d737fe2fe0d31992d3eefe85252ce24fa8e5bb650b450341f311c1df77d6146e70d352f8b0be9bd14096525b64c41c0a7b57f90a4fb72ca29cd5a79467a50a93fb405944ab2d37c822f5573d8f126c202d822d902dd868a7ad647fd9ff39f1823e3afb7c40e3f6ea79605d34293a8d2b3efb97123be728fbd43da3ed107beb672aa263af1abe2b6f36b2ba55cf647e9cac87ce56e1596b296c57451f62c95e5a3bc81211b059572cde1482f43e95b17bbc8946adb9f503090fd6c025e943cab839e51f8609c9e844d47dfb63afed3d9a5654d032d6a0a25c82be488608b9e69ca4c0487f383a17a4b67ae3d76e124bfa373201a9e3e3806c2b1f774535f30361f24093b77a733166b7cea316b7e062682a6db3bb895f0e4112aacee63c34080a8eecb1571395623755b986ae53625aa153c6946c96f779a015103f32092a8a70a272b5f929bb566b5fe26d7cf8038b61acf9b4e334d3d322ae5d6580c2f78f568831369938ce86efcccffd12bf3fa1d02680e5bf678706a76af23ae184f26477eb9789d0cd9bf259d5e7877a969b6a9dd1e60f742a90321d34feaef9a73addca681ea6cb0c1647fcf587e99b3b6f5884848ed96fe44dd040861069dbf051fc29d9bbca6736c80f96564cadd93d2731ab3a33629d968b122fd2f38e2ed2cc945e3cbed77d3ccdd2fe336aed48539f00437efe19e02a079331f9030187fbf0b8fbd119e442ecf58ab8fd6ceed82b7ae86b630647239851ebd569a8e66e7c8095d072478848f4cad5364341adec6f86df05583a1ccba313ac0b24d19b806e7a0385f8a9e850b3eb8b085d7c8dfcc051cd6be4d4a2b5c6626e3ad37b763231ce20e180853f6a9c6d496add04041ff1f8fd49a822cb8435e14929c8bfcb561c294588c9ebb8d4dcc11eca6ab7bc7d50a98b719ac8c44272b9df518a53b0abe44581caa7cb10edb77e92f08a6e9561a16e63fd7da2c998180bf05140ad55f47612fcc41d9691354e39b11f636b80eac1cfff252003ea335dbc4967627540519645e30e8fad215f7376035288aa77685ce36f7534187d943c2095ef79f5646a29719f4b2768da4239cec4c4d32167bedca132b64f5905ea83fce2ffe1fffe72962a6e97803bbea97ecd7f5a3ae8694b6118a7236a64c993bdb8418c02ac1d8f2f88f886e7549d06df2fe7c15256de84bbfe1586099ef97eab25dfe77526c4bbe6014540d299ad16b92e7558cecf9da1c0962aee51aaba1a52e13a6a28b3592d84c9dfade814748c3b8c07827fc97e8276e817a57ce217c80a34a3cc351daa2c59effe946b4e95f8c360b362ebe511f0d9fb605c69a66fa5b8ec154b2f4e810fed0259fc9753937a15f94ee5ee8efcc1194eccdd8529badb5140eeac7b4ba8470677593eee76f043609e7b0b901ac3314f912e5abdf9b7a221a517e83bd343537cccea9c6a301646288ede200e642ec2d3bd54caced8bd6252b806711616f5431c99bbfe571c5f37913d04e9bcb19c0243b7e998320ae078e6b4b275e5fc25c79ec7f45e21713b9d6a331ed8731ad57d88b78966aadca63ff85facf6579dd3bd392139a14c9f713cbdeaca096e2efe9967a87cc7e65f981b064bb7fc1f814893fb1f802ba7ac2ea0714187d99714f8313cbd31d2ab5654e9807dc6907582109f5935a65a67e79040083a80a8ed50230903a0a7286e1e6bf05c83be9c624007184ae35ed81249f608b90d3e7987fb3230a596eff529caf358ec81df37d89122040a2e27bf2a60a8456906dc6ec79b7c7abbe088f5236b433524283cc27075741d916caa629d2cdb2ada2d4c4e08a25eac0c60db8aa745e440edf2d9e3e1c51f060f2e8d2dfd039a56a56591d922a0d14df70832d538d407d5dbb565ccbb47a2a0251d07c1dcae9ad2c61ff8371bb74aec08bb5c98bb0a96a4c8d6b36806f52f376b4a56e922731611c65093d9c76d897b43bca4bf5d704480c7a5b4ab7ee1e391c742b9b19115a0cc329ba9e9b0d79b17c4a82d28471181185fd8cdcf25658ef061d44b5e455cce00f9f4eacd5309039661cef5615d464ce3d647e5aab91de2a8271adc3cbac1a8c5dd6cc3b72fb9b6d3194ae27d4a149c776ed191a7f9bd814bfb149e0f363bf6e8ad097aafe9d847f1d05ffcbc543e5651e86b11a23cefec193fdd83ea2590dbcd787e8beadb4834f8a15025a43d45ca3ab11679901d2c4815107f39b3ff86141fa12f7b1fce77b343e2bf3c99bbc4586cd10cec1a334f0d4f244e8c5b9e9786192817d68272c57c21f268ea3f8ebb8654febd3350eaff13ee1be007f6ef6d73f0fab1793b0e8035de450f112596baafcbf42c30ad92bdc652a2b7202bfa5fd4d8f58c987b61c6dd958ba8d8d14ddd3545d95ddaa2dc7197aee89f9691cc8141b81310b86f97e2c6ef93102bccc1a7b9c8143274f276c7dbe1025e9984c20b894b77bc8f3372ba2b42a803411793f40a8ede48ed4e9b122f54436ee5cbbdfef23bcfa061c778a3654e70786be1445057b9a0ae5c109356a98f55a5fbbc32449adb2b5f6af052bdb6f67f9f29e852119e81df7e05288a825fc9ebc027b62fb4a13620b7d5895d5a9229399aeea5bee7dacd7563abc55a56e4ddb086e1c383b3e5a6e8e96b3bee7202372b2ccfb057198a2b7bfd7e8eb0004134b575f748dbed4dff100153f40506377bdcadc527789a4b7c6e80a263e496aa5aee3f704092136728d8ebcbfe9000b111a263037404a", + ), +] +mldsa_params = [pytest.param(*k, id=f"{k[0]}/{k[1]}") for k in mldsa_keytypes] - # Create new root version. Replace the correct signature with one that looks - # reasonable for the keytype but is incorrect. Expect client to refuse the new root. - repo.publish([Root.type]) - root_md = Metadata.from_bytes(repo.signed_mds[Root.type].pop()) - root_md.signatures[signer.public_key.keyid].signature = bad_sig - repo.signed_mds[Root.type].append(root_md.to_bytes()) - assert client.refresh(init_data) == 1 - assert client.version(Root.type) == 2 +@pytest.mark.parametrize("keytype, scheme, bad_sig", mldsa_params) +def test_mldsa_keytype_and_scheme( + client: ClientRunner, + server: SimulatorServer, + keytype: str, + scheme: str, + bad_sig: str, +) -> None: + """Test that client supports ML-DSA keytypes""" + _test_keytype_and_scheme_internal(client, server, keytype, scheme, bad_sig) def test_invalid_sig_in_valid_metadata( From 9b36a9e855b1355c562f819652537fd38a6bd93e Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Thu, 9 Jul 2026 17:47:27 +0300 Subject: [PATCH 2/3] test_keys: Enable ML-DSA keys only in the ML-DSA test Signed-off-by: Jussi Kukkonen --- pyproject.toml | 1 + tuf_conformance/test_keys.py | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ac4d2c8..0ce9858 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,4 +39,5 @@ lint.select = ["ANN", "DTZ", "E", "F", "FA", "I", "N", "PIE", "PL", "PYI", "RET" lint.ignore = [ "S101", # assert is fine in pytest tests "PLR2004", # magic values are ok in a test suite + "PLR0913", # too many arguments ] diff --git a/tuf_conformance/test_keys.py b/tuf_conformance/test_keys.py index ac1fafe..a8adcc0 100644 --- a/tuf_conformance/test_keys.py +++ b/tuf_conformance/test_keys.py @@ -1,4 +1,6 @@ import json +from collections.abc import Generator +from unittest.mock import patch import pytest from securesystemslib.signer import KEY_FOR_TYPE_AND_SCHEME, SSlibKey @@ -205,14 +207,20 @@ def test_keytype_and_scheme( _test_keytype_and_scheme_internal(client, server, keytype, scheme, bad_sig) -# ML-DSA is not yet enabled by default in securesystemslib: enable for the test -KEY_FOR_TYPE_AND_SCHEME.update( - { - ("ml-dsa", "ml-dsa-44/1"): SSlibKey, - ("ml-dsa", "ml-dsa-65/1"): SSlibKey, - ("ml-dsa", "ml-dsa-87/1"): SSlibKey, - } -) +@pytest.fixture +def enable_mldsa() -> Generator[None, None, None]: + # ML-DSA is not yet enabled by default in securesystemslib: enable for the test + with patch.dict( + KEY_FOR_TYPE_AND_SCHEME, + { + ("ml-dsa", "ml-dsa-44/1"): SSlibKey, + ("ml-dsa", "ml-dsa-65/1"): SSlibKey, + ("ml-dsa", "ml-dsa-87/1"): SSlibKey, + }, + ): + yield + + mldsa_keytypes = [ ( "ml-dsa", @@ -240,6 +248,7 @@ def test_mldsa_keytype_and_scheme( keytype: str, scheme: str, bad_sig: str, + enable_mldsa: None, ) -> None: """Test that client supports ML-DSA keytypes""" _test_keytype_and_scheme_internal(client, server, keytype, scheme, bad_sig) From 03ff14256bd5d4c7c289862b742e27c88651dfd8 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Thu, 9 Jul 2026 17:48:14 +0300 Subject: [PATCH 3/3] selftest-client: Enable ML-DSA for now to test the test suite Signed-off-by: Jussi Kukkonen --- clients/python-tuf/python_tuf.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clients/python-tuf/python_tuf.py b/clients/python-tuf/python_tuf.py index 278ef33..d0e4f74 100755 --- a/clients/python-tuf/python_tuf.py +++ b/clients/python-tuf/python_tuf.py @@ -10,8 +10,18 @@ import shutil import sys +from securesystemslib.signer import KEY_FOR_TYPE_AND_SCHEME, SSlibKey from tuf.ngclient import Updater +# ML-DSA is not enable yet: enable to test the test suite +KEY_FOR_TYPE_AND_SCHEME.update( + { + ("ml-dsa", "ml-dsa-44/1"): SSlibKey, + ("ml-dsa", "ml-dsa-65/1"): SSlibKey, + ("ml-dsa", "ml-dsa-87/1"): SSlibKey, + } +) + def init(metadata_dir: str, trusted_root: str) -> None: """Initialize local trusted metadata"""