From fa2c43dda663b52f2aff968b4eea0d99f1c741de Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Thu, 15 Jun 2023 21:02:09 +0300 Subject: [PATCH 01/11] Add test repository data This change adds repository data to use in unit testing, keeping it the same as in python-tuf Signed-off-by: Ivana Atanasova --- .../repository_data/keystore/delegation_key | 1 + .../keystore/delegation_key.pub | 1 + testutils/repository_data/keystore/root_key | 42 +++++++++ .../repository_data/keystore/root_key.pub | 11 +++ testutils/repository_data/keystore/root_key2 | 1 + .../repository_data/keystore/root_key2.pub | 1 + testutils/repository_data/keystore/root_key3 | 1 + .../repository_data/keystore/root_key3.pub | 1 + .../repository_data/keystore/snapshot_key | 1 + .../repository_data/keystore/snapshot_key.pub | 1 + .../repository_data/keystore/targets_key | 1 + .../repository_data/keystore/targets_key.pub | 1 + .../repository_data/keystore/timestamp_key | 1 + .../keystore/timestamp_key.pub | 1 + .../repository/metadata/1.root.json | 72 +++++++++++++++ .../repository/metadata/role1.json | 49 +++++++++++ .../repository/metadata/role2.json | 15 ++++ .../repository/metadata/root.json | 87 +++++++++++++++++++ .../repository/metadata/snapshot.json | 25 ++++++ .../repository/metadata/targets.json | 61 +++++++++++++ .../repository/metadata/timestamp.json | 23 +++++ 21 files changed, 397 insertions(+) create mode 100644 testutils/repository_data/keystore/delegation_key create mode 100644 testutils/repository_data/keystore/delegation_key.pub create mode 100644 testutils/repository_data/keystore/root_key create mode 100644 testutils/repository_data/keystore/root_key.pub create mode 100644 testutils/repository_data/keystore/root_key2 create mode 100644 testutils/repository_data/keystore/root_key2.pub create mode 100644 testutils/repository_data/keystore/root_key3 create mode 100644 testutils/repository_data/keystore/root_key3.pub create mode 100644 testutils/repository_data/keystore/snapshot_key create mode 100644 testutils/repository_data/keystore/snapshot_key.pub create mode 100644 testutils/repository_data/keystore/targets_key create mode 100644 testutils/repository_data/keystore/targets_key.pub create mode 100644 testutils/repository_data/keystore/timestamp_key create mode 100644 testutils/repository_data/keystore/timestamp_key.pub create mode 100644 testutils/repository_data/repository/metadata/1.root.json create mode 100644 testutils/repository_data/repository/metadata/role1.json create mode 100644 testutils/repository_data/repository/metadata/role2.json create mode 100644 testutils/repository_data/repository/metadata/root.json create mode 100644 testutils/repository_data/repository/metadata/snapshot.json create mode 100644 testutils/repository_data/repository/metadata/targets.json create mode 100644 testutils/repository_data/repository/metadata/timestamp.json diff --git a/testutils/repository_data/keystore/delegation_key b/testutils/repository_data/keystore/delegation_key new file mode 100644 index 00000000..461169d6 --- /dev/null +++ b/testutils/repository_data/keystore/delegation_key @@ -0,0 +1 @@ +68593a508472ad3007915379e6b1f3c0@@@@100000@@@@615986af4d1ba89aeadc2f489f89b0e8d46da133a6f75c7b162b8f99f63f86ed@@@@8319255f9856c4f40f9d71bc10e79e5d@@@@1dc7b20f1c668a1f544dc39c7a9fcb3c4a4dd34d1cc8c9d8f779bab026cf0b8e0f46e53bc5ed20bf0e5048b94a5d2ea176e79c12bcc7daa65cd55bf810deebeec5bc903ce9e5316d7dbba88f1a2b51d3f9bc782f8fa9b21dff91609ad0260e21a2039223f816d0fe97ace2e204d0025d327b38d27aa6cd87e85aa8883bfcb6d12f93155d72ffd3c7717a0570cf9811eb6d6a340baa0f27433315d83322c685fec02053ff8c173c4ebf91a258e83402f39546821e3352baa7b246e33b2a573a8ff7b289682407abbcb9184249d4304db68d3bf8e124e94377fd62dde5c4f3b7617d483776345154d047d139b1e559351577da315f54e16153c510159e1908231574bcf49c4f96cafe6530e86a09e9eee47bcff78f2fed2984754c895733938999ff085f9e3532d7174fd76dc09921506dd2137e16ec4926998f5d9df8a8ffb3e6649c71bc32571b2e24357739fa1a56be \ No newline at end of file diff --git a/testutils/repository_data/keystore/delegation_key.pub b/testutils/repository_data/keystore/delegation_key.pub new file mode 100644 index 00000000..d600bffb --- /dev/null +++ b/testutils/repository_data/keystore/delegation_key.pub @@ -0,0 +1 @@ +{"keyval": {"public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key b/testutils/repository_data/keystore/root_key new file mode 100644 index 00000000..1b8fb145 --- /dev/null +++ b/testutils/repository_data/keystore/root_key @@ -0,0 +1,42 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIHbTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIsnvMDGLfuE8CAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBN6jE1eBpMFrFfAs0FkzHQBIIH +EAacUao28rDMs/rL1H4hrWN6OqkcAzjMG/dNDDiLtljpHsYHYWg417cz4eVsWVw7 +SzP005D5qu78oBa35Yg22zW3vlHS1RDlPKFpYrFliwgaWaxVx7CrKhGXq8CeoCnS +aymN43o493TExHUOGgjTU7eLPXk8eVZ5aO+ml+i/YyPldrEwcghsBDD27zwXOgZk +qwFoCxCWVUCRcywaTGGvRQ13GVcLYlj+CjTzp2ctXzcWhGK77kPhtVFXpGO00vVn +7i2kyZm8tLXXFJ+fAMm3OCyyIUnFlf2KuYRECksUvGbscgIH/W2O6qvq7klgappB +xiyI8dlBeOboxtdbnqoSkodac0pfY8a7b0SIw5H6U/2hiNEQx2o/gFMFq8OklwiW +gO3PCjtG/bXFYqBjzBtBdAQ77UEv3pbeZNReLx7gCn7YIyLQ5ltqG2Kmbp8pb08w +hFJm6CcHkBP4GkfzNGtagJCbqX0ys5yG2DxqGZAGPynydwr3EbrvF8UToAaVpgR4 +7RqVk/uZf48UM6M/I8Q0aHz1fja9pwY7H/syyBs2R3Pn98O2HxZ8futqxefCImbs +DL6cd+VCFjmgsIQBYku2eqYEm98MLWHsiLbNPnyjgmrMElBVWNBlYsYXxqgL+lR1 +fvNBZlYCr7ZthfD+DtxmRU3rApl2Hi22x5IwI7N/4B3/+nRKJLRoc1gW+kekE91j +PRB30iLR+a5FkFA0u6ymRw7TvYY2u8Y8zbWwhC1rtCTCDcFAOGMGiDxSwbJX7e9y +cjGPZH+9daNEH03B51MlGwPee511ehtMa1RhWWCGsMsWzeOpIqy1yzPxGkAO0+Wo +ReNgtlOcjKanW6gdOpiGAeZRKBBYKZhAj8ogs958ZWYRVpNUzNs8ihMRuH4PSJzE +BrJFqgvk+YXwZFLw2ugZmjPRdjbCJOVdh25xAMy+hrlL4ZwWT50WHYsfGDUeM/kq +uwidpU94Xi4C5MJww0Z7grztbmUqRqNGiPyqGakgB7LtEwPICOaxeHSYOu+PTklF +0Sl2aEH7VuptfVknndd8AX0ozMrSFe0jh5I5CA+Bu315EJfHgHiYB31VpKKpY6Bn +Naeb2rH+CpajLNC7ULcDRpHRZNkolX6nHLf63PGPhD6x1HdJWlfQAXk7+mNFtVZ5 +ugXD/6Hei9w0JYAbPr0Up2tw2KPIRW75CFJdpIwqTdV20ZfP4kbUZOfOK9ltWyB1 +2q6OXliEfvzRYXI8TbUfZ6RpgH6j8VWia/ER/q4O0cKoQ5UfP3RgKil2Jz3QJTYe +E6DVJkv5NtSRK7ZkdtI8SZCkOQ0Rhz0NKmQhDlftoQOYWmLkPJenQVNxra6hOO2l +6cZ2e1AVv+8csR/22Qipve8IRfqLsH48dKP3cXZSM/7CaF/q1Wgkc+nZBOLVpK5P +Q6+bCljxtdlbR5bzTrbz2ELorGCH3bNg+O73MD27wtNbkb2ZmleVXc5WU733CKr1 +8edMWaAtWMkLNUlCJ8bnBOGb2sIy9PXzEWn1kECDhQSgcSaBnIglU03z/5/9HLpc +8lpC0yUTIhwX0zr8G0ZpirIcfvjNhq4qksR8bahc8eNkf6Rn3sB4E8uSv0UbxG/V +OibWXabyb5t5J261+WWmalz02Q4iQso0YIUOZBiKAlY4mIf2sWQX4rFSWconYBb5 +me5+BBVfJN7WO0RGG8aliqj8op/BkwhS2P1cWKntIm7DWKr5QyU/oj044ZpxkwZd +TL5n+puYkijgUkcvab+ew9x+f3speWdv2a9Zuk3mKEO4TcKnchE/4M/mIzoX/bmI +KLsZ2c7WUySfGzFBEZUY6NUR3bkehIDOY7fCnS0Dz7rSbImNVsMp8QbgANvK6YL8 +M6MJfZKWh6VEBm2athFV8Rc+q1Bf0VMO5+/8ay+GSFN+EIbPZZOwmNpzlIg6m0LS +ix+7/k1H3vjHwhxRa3g/2vqoY/mwdvjb1+bMsejygGV0vF57R5Zlm842ZWPaVQYz +T5gElaP+BXDIo7pkXMOrvr9oKkDFWPhhKpfzm94i5QUpYGJIbr811e4tQzh9WfrX +nnaARPhUrE+Yhy5ghWMDwA8So2FoUlCzS9zAW5cgMPdwvn/zraY0HCp8wGW/yNl6 +jhwSvmUa2SnQkPuR977lkWodLOU9mwOnvZqplmhprh4w+znoPcuTNM5XQ7Rxulfx +ZOJZ7NjLr3t2gY2Ni4Su961GcG9/1qgb/gbh+epzpIWaMSfJhXwBv/TmDppg1IB/ +q1Y2ICtZX0V6/szszPsPpBcqRpMAa6T12pL/J6OVYcnSrX6lzY8uVzM4Va1M/Fwn +C45VwvBK0StZY2T+CWdAoG20wA9IJhSr8xajCxR1UNsNgrQ84dJN6KduURbNmMTM +m5fryjMFAoykt+cz1TOq7G3sFLslYkWH8DP1mdknC1uC +-----END ENCRYPTED PRIVATE KEY----- diff --git a/testutils/repository_data/keystore/root_key.pub b/testutils/repository_data/keystore/root_key.pub new file mode 100644 index 00000000..11cc245f --- /dev/null +++ b/testutils/repository_data/keystore/root_key.pub @@ -0,0 +1,11 @@ +-----BEGIN PUBLIC KEY----- +MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe +PkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i +xmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity +fQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa +ndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc +MdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV +z94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y +R47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA +a82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE= +-----END PUBLIC KEY----- diff --git a/testutils/repository_data/keystore/root_key2 b/testutils/repository_data/keystore/root_key2 new file mode 100644 index 00000000..82229465 --- /dev/null +++ b/testutils/repository_data/keystore/root_key2 @@ -0,0 +1 @@ +77c02ab5647ee765d5f6c5fc202a5b32@@@@100000@@@@7c73c1100fab52dc8695c1b955d31770ed6e53f1820d9020aeb6541c948573d9@@@@98280307ffa9c5f6ff1fea1a4b79d0ea@@@@f3342882b1cf842e3377ab4205c0ca8fab564cc55fa742f55b364a1ac597e93d8c56a9a6e6bbb6a812556077be44a1066ac6781a6ed34b86beaf3985f846f007dab31c46af562e921f03c1ea8d299f15324ab137aa426ee61d396a7e20191aa71a70b670775b2ad48f25de367fb48881c55e93f468c6e59402907e82985c27c94c715161c85c5c1904353ba33c3d129988029f03a2d7d00720118697baaf73a3c4e72f8e538b4323866fe525ddccfcfc6dd45598545f65cd7ab581f5172bc253416283a66621eb03dbabaf33923bb1963f9f8cbae6fd6a1c86736a8f80c8d1ba3cbc3f53b0123ba9b0bdd44f25b65033b19a50ee978d2687d6a2ee724515a20026d0213ced59cda9bfdf37c82c59e1356795fd603d85996f448a3c9357b32de2042997a1d27353ee3866c0ed5218d633e0b28991119d77d147354c7fa2de8a168d17efdfd5fa9a8e528bd47ede4ff697 \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key2.pub b/testutils/repository_data/keystore/root_key2.pub new file mode 100644 index 00000000..dd5c43b5 --- /dev/null +++ b/testutils/repository_data/keystore/root_key2.pub @@ -0,0 +1 @@ +{"keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"], "keyval": {"public": "3ba219e69666298bce5d1d653a166346aef807c02e32a846aaefcb5190fddeb4"}} \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key3 b/testutils/repository_data/keystore/root_key3 new file mode 100644 index 00000000..89c0b2cc --- /dev/null +++ b/testutils/repository_data/keystore/root_key3 @@ -0,0 +1 @@ +a3d266f446cb23c0248feed240a8a85a@@@@100000@@@@61ea41c73d4b1d8bd7566a9884a2fdb88c1d4e48550341e532768f98c8f4bd3c@@@@46b15764c50c934fcfc041a5fa207337@@@@d84b8c473d5f42d2bbceca28b0087c2c5908673b2a92eb8f1ca91dacc27c1cfac24c98d06191f6f54633dd428e9ca0987f183e8f34322a104dc38a0f4fefcc168f21e203e3abc5842f132df2dcb61d6b31dc19d0ecb50e898655f81e9b8a9730f2bff4c5ca4b6fc0b572a7e3672b6dc814ed127c964d960a57155c29eccf44824442d3c6761662ed2d8a1c48a3222d0f0cb1a58f543ccd852c247522595d987d95d1bf49dfdffaf33f18085460dac791d81347cc576a83c6ebca2625d26ddd294e74fa67f676a02d533b52fc9702237b2c898469a30753d98b091cd6aa713aa7b0c4c741684674084b27862e64adf4b1e88fa22cfcf6eeae8608dd818a4cba020058fa7271028ea9d9a7302c9e50e82972a82ac2080201c0fb9f2fb1cadfe97d62470414428227add1c40594f5135a8169d0d7d0889cb4a1949b015e65f5dc656204c58c463acc5b7872f4a078d0bc5a09a7795187e360e7b225892601aa9065086b24397f653d20e59a656ec86ef94e64d5baf16080f12a7f2461b92f99dfb5bf2e4dadec91cc72d8eede952449fd586c863734d84f31e036ecc96c55ab7baa9b049c20b8281a7c28f5ca42d9cfad6498f51ee907bfd9dc17e2a1bc9b69145ee82a86a90817394c01770581727889d3ba1791592c7ac2e74753485f1811cc4477078732873185240fc1572927d2fef210066bdf015471bd9d1683e8074b3fb6957246589dc62dea4843a17a7c734ae45ae20d31f0083a32d3310fae459fe3fbf7c763e5e4ead4acd9b0233e45237f4465576e85ff707fe316488f329d5bc73596b104cc28b926d6b1f5a3d26a0a6ec534a3cbc54cab97f5cea51f17b8d7f1cc6c9977275c34ee4942dd3e22a19ae1e4252199226cc4fd60 \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key3.pub b/testutils/repository_data/keystore/root_key3.pub new file mode 100644 index 00000000..ee5d4872 --- /dev/null +++ b/testutils/repository_data/keystore/root_key3.pub @@ -0,0 +1 @@ +{"keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": ["sha256", "sha512"], "keyval": {"public": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4huWFUZelzzZk2xLwnLqyc2q7cfI\nIqgg3qOWSddQ3Q/GBXCzgg7zqNqS+xSt+D3gy3mMBbkeo+6OVm8/W9BrqQ=="}} \ No newline at end of file diff --git a/testutils/repository_data/keystore/snapshot_key b/testutils/repository_data/keystore/snapshot_key new file mode 100644 index 00000000..08c954fd --- /dev/null +++ b/testutils/repository_data/keystore/snapshot_key @@ -0,0 +1 @@ +a87b80b8a0d39b919b9638181e7b274e@@@@100000@@@@132edd670981aaf1980673966266174d944d735eb5b0b7ec83ed97da5c212249@@@@bd08ae9898ac5f81fc14e418e9790f9b@@@@399250c9aad40035e0acff48db59697bc3cf33d55b52aa272246addeaaf318d931d3a72964f0c84eccf5b89279b8233685330ad884f7b39bf369553133b985f9396bd5e24cb8e343643923022565a645e188a1165e427aedc389cca821d6a93cb2d8d16cea8ffeb56469bcb9f2f66e03d581a2ea37da271980dd02b84717fe475e13a305b4ae714c11c94f6711c744bb291a146d7419474584bad4be152d0299273c1fad6cd95232a4bf07f39c16da7f4d13201a88fad822cb328008e8a2762baf974b5d5080451751fb8ef53a01ca734157be78b3eb13c6270e4e98b138c78388360e7f558389871b7a32b4d5572626b3112264a0b56dbbb1138c9765872a71dd4e7d31006c2e690f5ede608ce633ad94ebb7d1ddec1a7eac2168fc5d36efe590c4c2059c6f3bcf75ab63474eede3ce4fdc93c6564058b14a0fa9bf3cb6d58c53315b406409ee4aeb18abe072734df0 \ No newline at end of file diff --git a/testutils/repository_data/keystore/snapshot_key.pub b/testutils/repository_data/keystore/snapshot_key.pub new file mode 100644 index 00000000..d08bb848 --- /dev/null +++ b/testutils/repository_data/keystore/snapshot_key.pub @@ -0,0 +1 @@ +{"keyval": {"public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file diff --git a/testutils/repository_data/keystore/targets_key b/testutils/repository_data/keystore/targets_key new file mode 100644 index 00000000..c3883ec3 --- /dev/null +++ b/testutils/repository_data/keystore/targets_key @@ -0,0 +1 @@ +a5a903322888df0bf8275b215f2044fe@@@@100000@@@@5f6b803652cb6d5bce4e07b1482597adb96d06c2efa3393abdcc0425f70be692@@@@0664811967e2f413927ce51a7f43a80e@@@@cf1dccd034400195c667c064198ef25555f3f94bf9cf77fbe300246618e557ad0efa775ef90bd46c842696c45d14033199860b2214c3641e87889a41171f8a2c763d004681b66b462ff34599e8d9da87f5642d2a015b75d3f601d198e0467fa4bc28f65c76260585e0cce71281f67a8053116f0f06883155f602811071b56bf75bf54daae5968b0a31cf829510f3c52c0eeb8f1c6bb8b8cb0c3edb4c6c2dd9d13bee00c5d63c3f98e0904eebb609864f4ab4fcc2c17bba8fd36aa06bc96bc1922eb10557051a674acf2cb01ff3efb7d55411df6915bbc49a095ff4472dc441e2765244f801d0df07b754c952d039f39b4530930a14be42cb2041f22eeb306b12f12158fcd2beb033db1be21f5a6ab72335cf16dfbd19cbf39c00b0a571d2b0e25df032be53a49a7a70ecebebb441d327c638cf31804381afaf809cd1c75f9070e83240fbaaa87bea0799404ece788862 \ No newline at end of file diff --git a/testutils/repository_data/keystore/targets_key.pub b/testutils/repository_data/keystore/targets_key.pub new file mode 100644 index 00000000..e859eb22 --- /dev/null +++ b/testutils/repository_data/keystore/targets_key.pub @@ -0,0 +1 @@ +{"keyval": {"public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file diff --git a/testutils/repository_data/keystore/timestamp_key b/testutils/repository_data/keystore/timestamp_key new file mode 100644 index 00000000..ca825790 --- /dev/null +++ b/testutils/repository_data/keystore/timestamp_key @@ -0,0 +1 @@ +677a42cd6c1df08d0c6156ae356c2875@@@@100000@@@@3850dbcf2973b80044912d630f05039df64775b63d1cf43e750d3cd8a457c64f@@@@bf01961c386d9fefb4b29db7f6ef0c7f@@@@96d37abafb902f821134d2034855d23b78c82e5b768b092fcf0d3b6b28a74734877a5014b26e5fed289d24f7cf6b393445c3231554c5b6d9711192cf9bd2fb7490497d7d76c619a0cfc70abae026b5068fb66db0138b04f890917daad66ca1f7baabdcbb5282e46a2f1c6ff2e8c241ff16ef31e918ca1387a15bc2ceadb2f75ce68fcff08186b5b901a499efe1f674319b503ff8b6fc004b71d0ecb94253f38c58349ab749e72f492e541e7504d25a0bfe791f53eb95c4524431b0f952fc3d7c7204a2a4aab44d33fe09cb36b337339e2a004bf15dfd925b63930905972749441a0c6e50ec9b1748a4cfbacf10b402ebd9c0074fcb38d236fd3146f60232862b0501e8e6caa9f81c223de03ba7b25a1d4bc2d031901dc445f25ce302d2189b8b8de443bc6f562f941b55595655193ab6b84c1ec2302ca056c70e8efb1cad909c50e82e0b7da9ad64202d149e4e837409 \ No newline at end of file diff --git a/testutils/repository_data/keystore/timestamp_key.pub b/testutils/repository_data/keystore/timestamp_key.pub new file mode 100644 index 00000000..69ba7ded --- /dev/null +++ b/testutils/repository_data/keystore/timestamp_key.pub @@ -0,0 +1 @@ +{"keyval": {"public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/1.root.json b/testutils/repository_data/repository/metadata/1.root.json new file mode 100644 index 00000000..9adb68b3 --- /dev/null +++ b/testutils/repository_data/repository/metadata/1.root.json @@ -0,0 +1,72 @@ +{ + "signed": { + "_type": "root", + "consistent_snapshot": true, + "expires": "2030-08-15T14:30:45.0000001Z", + "keys": { + "0a5842e65e9c8c428354f40708435de6793ac379a275effe40d6358be2de835c": { + "keytype": "ed25519", + "keyval": { + "public": "4e10fe156f07e6f6e1f6fb1579105b7d3e62790b6a62dbf7727b91f82d2bc9db" + }, + "scheme": "ed25519" + }, + "409fb816e403e0c00646665eac21cb8adfab8e318272ca7589b2d1fc0bccb255": { + "keytype": "ed25519", + "keyval": { + "public": "23e5dc4eb18d5c116e76a92b02e44a7d7279622574457050b85fb8fd9260422c" + }, + "scheme": "ed25519" + }, + "700464ea12f4cb5f06a7512c75b73c0b6eeb2cd42854b085eed5b3c993607cba": { + "keytype": "ed25519", + "keyval": { + "public": "1603f99998ca46c35c238a2c1a2a015e0f32b38771e4fa5401348ce0a677d63f" + }, + "scheme": "ed25519" + }, + "d5fa855fce82db75ec64283e828cc90517df5edf5cdc57e7958a890d6556f5b7": { + "keytype": "ed25519", + "keyval": { + "public": "17454b5e7a6594e7f00ceadda10d0267b94d0118b82f541f4f69f0d327c5a41a" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "d5fa855fce82db75ec64283e828cc90517df5edf5cdc57e7958a890d6556f5b7" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "700464ea12f4cb5f06a7512c75b73c0b6eeb2cd42854b085eed5b3c993607cba" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "409fb816e403e0c00646665eac21cb8adfab8e318272ca7589b2d1fc0bccb255" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "0a5842e65e9c8c428354f40708435de6793ac379a275effe40d6358be2de835c" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.31", + "version": 1, + "test": "true" + }, + "signatures": [ + { + "keyid": "d5fa855fce82db75ec64283e828cc90517df5edf5cdc57e7958a890d6556f5b7", + "sig": "1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee" + } + ] +} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/role1.json b/testutils/repository_data/repository/metadata/role1.json new file mode 100644 index 00000000..0ac4687e --- /dev/null +++ b/testutils/repository_data/repository/metadata/role1.json @@ -0,0 +1,49 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role2", + "paths": [], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": { + "file3.txt": { + "hashes": { + "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", + "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" + }, + "length": 28 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/role2.json b/testutils/repository_data/repository/metadata/role2.json new file mode 100644 index 00000000..9c49e165 --- /dev/null +++ b/testutils/repository_data/repository/metadata/role2.json @@ -0,0 +1,15 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" + } + ], + "signed": { + "_type": "targets", + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/root.json b/testutils/repository_data/repository/metadata/root.json new file mode 100644 index 00000000..d1cba02a --- /dev/null +++ b/testutils/repository_data/repository/metadata/root.json @@ -0,0 +1,87 @@ +{ + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + }, + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ] +} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/snapshot.json b/testutils/repository_data/repository/metadata/snapshot.json new file mode 100644 index 00000000..251e99cf --- /dev/null +++ b/testutils/repository_data/repository/metadata/snapshot.json @@ -0,0 +1,25 @@ +{ + "signed": { + "_type": "snapshot", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "role1.json": { + "version": 1 + }, + "role2.json": { + "version": 1 + }, + "targets.json": { + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + }, + "signatures": [ + { + "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", + "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" + } + ] +} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/targets.json b/testutils/repository_data/repository/metadata/targets.json new file mode 100644 index 00000000..d18b7b52 --- /dev/null +++ b/testutils/repository_data/repository/metadata/targets.json @@ -0,0 +1,61 @@ +{ + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role1", + "paths": [ + "file3.txt" + ], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": { + "file1.txt": { + "custom": { + "file_permissions": "0644" + }, + "hashes": { + "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", + "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" + }, + "length": 31 + }, + "file2.txt": { + "hashes": { + "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", + "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" + }, + "length": 39 + } + }, + "version": 1 + }, + "signatures": [ + { + "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", + "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" + } + ] +} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/timestamp.json b/testutils/repository_data/repository/metadata/timestamp.json new file mode 100644 index 00000000..c1c5a4e1 --- /dev/null +++ b/testutils/repository_data/repository/metadata/timestamp.json @@ -0,0 +1,23 @@ +{ + "signed": { + "_type": "timestamp", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "snapshot.json": { + "hashes": { + "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" + }, + "length": 515, + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + }, + "signatures": [ + { + "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", + "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" + } + ] +} \ No newline at end of file From a8e7953c803f75ca83ad2c38ef135c97c5a40b72 Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Thu, 15 Jun 2023 21:03:30 +0300 Subject: [PATCH 02/11] Add file system simulator This change adds a mock for os functions Signed-off-by: Ivana Atanasova --- testutils/simulators/file_system.go | 91 +++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 testutils/simulators/file_system.go diff --git a/testutils/simulators/file_system.go b/testutils/simulators/file_system.go new file mode 100644 index 00000000..e4ec0b9c --- /dev/null +++ b/testutils/simulators/file_system.go @@ -0,0 +1,91 @@ +// Copyright 2023 VMware, Inc. +// +// This product is licensed to you under the BSD-2 license (the "License"). +// You may not use this product except in compliance with the BSD-2 License. +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to +// the terms and conditions of the subcomponent's license, as noted in the +// LICENSE file. +// +// SPDX-License-Identifier: BSD-2-Clause + +package simulator + +import ( + "fmt" + "os" + + log "github.com/sirupsen/logrus" +) + +// osFS implements fileSystem using the local disk. +type osFS struct{} + +func (*osFS) MkdirTemp(dir string, pattern string) (string, error) { + return os.MkdirTemp(dir, pattern) +} + +func (*osFS) TempDir() string { + return os.TempDir() +} + +func (*osFS) Mkdir(name string) error { + return os.Mkdir(name, 0750) +} + +func (*osFS) Copy(fromPath string, toPath string) error { + os.MkdirAll(toPath, 0750) + files, err := os.ReadDir(fromPath) + if err != nil { + log.Debugf("failed to read path %s: %v", fromPath, err) + return err + } + for _, file := range files { + data, err := os.ReadFile(fmt.Sprintf("%s/%s", fromPath, file.Name())) + if err != nil { + log.Debugf("failed to read file %s: %v", file.Name(), err) + } + filePath := fmt.Sprintf("%s/%s", toPath, file.Name()) + err = os.WriteFile(filePath, data, 0750) + if err != nil { + log.Debugf("failed to write file %s: %v", filePath, err) + } + } + return nil +} + +func (*osFS) ReadFile(name string) ([]byte, error) { + return os.ReadFile(name) +} + +func (*osFS) WriteFile(name string, data []byte) error { + return os.WriteFile(name, data, 0644) +} + +func (*osFS) RemoveAll(path string) error { + return os.RemoveAll(path) +} + +var fs fileSystem = &osFS{} + +type fileSystem interface { + TempDir() string + Mkdir(name string) error + MkdirTemp(dir string, pattern string) (string, error) + Copy(fromPath string, toPath string) error + ReadFile(name string) ([]byte, error) + WriteFile(name string, data []byte) error + RemoveAll(path string) error +} + +func CreateFile(path string, data []byte) error { + return fs.WriteFile(path, data) +} + +func DeleteFile(path string) error { + return fs.RemoveAll(path) +} + +func ReadFile(name string) ([]byte, error) { + return fs.ReadFile(name) +} From de182fd1af89bddf89e7feffdc3971bb38b82e6a Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Thu, 15 Jun 2023 21:04:41 +0300 Subject: [PATCH 03/11] Add test client simulator This change implements client simulator for working with local repositories Signed-off-by: Ivana Atanasova --- testutils/simulators/test_client.go | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 testutils/simulators/test_client.go diff --git a/testutils/simulators/test_client.go b/testutils/simulators/test_client.go new file mode 100644 index 00000000..34a96dcb --- /dev/null +++ b/testutils/simulators/test_client.go @@ -0,0 +1,61 @@ +// Copyright 2023 VMware, Inc. +// +// This product is licensed to you under the BSD-2 license (the "License"). +// You may not use this product except in compliance with the BSD-2 License. +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to +// the terms and conditions of the subcomponent's license, as noted in the +// LICENSE file. +// +// SPDX-License-Identifier: BSD-2-Clause + +package simulator + +import ( + "fmt" + "path/filepath" + + log "github.com/sirupsen/logrus" +) + +var ( + TempDir string + RepoDir string + KeystoreDir string +) + +func SetupTestDirs() error { + tmp := fs.TempDir() + var err error + TempDir, err = fs.MkdirTemp(tmp, "0750") + if err != nil { + log.Fatal("failed to create temporary directory: ", err) + return err + } + fmt.Println(TempDir) + + RepoDir = fmt.Sprintf("%s/repository_data/repository", TempDir) + fs.Mkdir(RepoDir + "/metadata") + absPath, err := filepath.Abs("../testutils/repository_data/repository/metadata") + if err != nil { + log.Debugf("failed to get absolute path: %v", err) + } + fs.Copy(absPath, RepoDir) + + KeystoreDir = fmt.Sprintf("%s/keystore", TempDir) + fs.Mkdir(KeystoreDir) + absPath, err = filepath.Abs("../testutils/repository_data/keystore") + if err != nil { + log.Debugf("failed to get absolute path: %v", err) + } + fs.Copy(absPath, KeystoreDir) + + // TODO: load keys to keystore map + + return nil +} + +func Cleanup() { + log.Printf("cleaning temporary directory: %s\n", TempDir) + fs.RemoveAll(TempDir) +} From 47cfa35a4a5789f3386f90c58b2b72d366b5009e Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Fri, 9 Jun 2023 20:35:46 +0300 Subject: [PATCH 04/11] Add metadata unit tests This change adds unit tests for part of the metadata methods Signed-off-by: Ivana Atanasova --- metadata/metadata_test.go | 320 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 303 insertions(+), 17 deletions(-) diff --git a/metadata/metadata_test.go b/metadata/metadata_test.go index 890a18c2..012eac15 100644 --- a/metadata/metadata_test.go +++ b/metadata/metadata_test.go @@ -12,13 +12,33 @@ package metadata import ( + "crypto" + "crypto/ed25519" + "crypto/sha256" "encoding/json" + "fmt" + "os" "testing" "time" + "github.com/sigstore/sigstore/pkg/signature" "github.com/stretchr/testify/assert" ) +var ( + testRootBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}") + testEmptyTargetsBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{},\"test\":\"true\",\"version\":1}}") + testSnapshotBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"snapshot\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"targets.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}") + testTimestampBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"timestamp\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"snapshot.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}") + testRootGenericMetadta = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"version\":1},\"test\":\"true\"}") + testTargetsFileCustomField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{\"testTarget\":{\"custom\":{\"test\":true},\"hashes\":{},\"length\":0}},\"version\":1}}") + testRootBytes = []byte("{\"signatures\":[{\"keyid\":\"roothash\",\"sig\":\"1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee\"}],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{\"roothash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubrootval\"},\"scheme\":\"ed25519\"},\"snapshothash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubsval\"},\"scheme\":\"ed25519\"},\"targetshash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubtrval\"},\"scheme\":\"ed25519\"},\"timestamphash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubtmval\"},\"scheme\":\"ed25519\"}},\"roles\":{\"root\":{\"keyids\":[\"roothash\"],\"threshold\":1},\"snapshot\":{\"keyids\":[\"snapshothash\"],\"threshold\":1},\"targets\":{\"keyids\":[\"targetshash\"],\"threshold\":1},\"timestamp\":{\"keyids\":[\"timestamphash\"],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"version\":1}}") +) + +const TEST_REPOSITORY_DATA = "../testutils/repository_data/repository/metadata" + +var fixedExpire = time.Date(2030, 8, 15, 14, 30, 45, 100, time.UTC) + func TestDefaultValuesRoot(t *testing.T) { // without setting expiration meta := Root() @@ -335,36 +355,33 @@ func TestIsExpiredTargets(t *testing.T) { } func TestUnrecognizedFieldRolesSigned(t *testing.T) { - // fixed expire - expire := time.Date(2030, 8, 15, 14, 30, 45, 100, time.UTC) - // unrecognized field to test // added to the Signed portion of each role type testUnrecognizedField := map[string]any{"test": "true"} - root := Root(expire) + root := Root(fixedExpire) root.Signed.UnrecognizedFields = testUnrecognizedField rootJSON, err := root.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}"), rootJSON) + assert.Equal(t, testRootBytesWithUnrecognizedField, rootJSON) - targets := Targets(expire) + targets := Targets(fixedExpire) targets.Signed.UnrecognizedFields = testUnrecognizedField targetsJSON, err := targets.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{},\"test\":\"true\",\"version\":1}}"), targetsJSON) + assert.Equal(t, testEmptyTargetsBytesWithUnrecognizedField, targetsJSON) - snapshot := Snapshot(expire) + snapshot := Snapshot(fixedExpire) snapshot.Signed.UnrecognizedFields = testUnrecognizedField snapshotJSON, err := snapshot.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"snapshot\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"targets.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}"), snapshotJSON) + assert.Equal(t, testSnapshotBytesWithUnrecognizedField, snapshotJSON) - timestamp := Timestamp(expire) + timestamp := Timestamp(fixedExpire) timestamp.Signed.UnrecognizedFields = testUnrecognizedField timestampJSON, err := timestamp.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"timestamp\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"snapshot.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}"), timestampJSON) + assert.Equal(t, testTimestampBytesWithUnrecognizedField, timestampJSON) } func TestUnrecognizedFieldGenericMetadata(t *testing.T) { // fixed expire @@ -378,17 +395,14 @@ func TestUnrecognizedFieldGenericMetadata(t *testing.T) { root.UnrecognizedFields = testUnrecognizedField rootJSON, err := root.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"version\":1},\"test\":\"true\"}"), rootJSON) + assert.Equal(t, testRootGenericMetadta, rootJSON) } func TestTargetFilesCustomField(t *testing.T) { - // fixed expire - expire := time.Date(2030, 8, 15, 14, 30, 45, 100, time.UTC) - // custom JSON to test testCustomJSON := json.RawMessage([]byte(`{"test":true}`)) // create a targets metadata - targets := Targets(expire) + targets := Targets(fixedExpire) assert.NotNil(t, targets) // create a targetfile with the custom JSON @@ -399,5 +413,277 @@ func TestTargetFilesCustomField(t *testing.T) { targets.Signed.Targets["testTarget"] = targetFile targetsJSON, err := targets.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{\"testTarget\":{\"custom\":{\"test\":true},\"hashes\":{},\"length\":0}},\"version\":1}}"), targetsJSON) + assert.Equal(t, testTargetsFileCustomField, targetsJSON) +} + +func TestFromBytes(t *testing.T) { + root := Root(fixedExpire) + assert.Equal(t, fixedExpire, root.Signed.Expires) + + _, err := root.FromBytes(testRootBytes) + assert.NoError(t, err) + + assert.Equal(t, fixedExpire, root.Signed.Expires) + assert.Equal(t, fixedExpire, root.Signed.Expires) + assert.Equal(t, ROOT, root.Signed.Type) + assert.True(t, root.Signed.ConsistentSnapshot) + + assert.Equal(t, 4, len(root.Signed.Keys)) + assert.Contains(t, root.Signed.Roles, ROOT) + assert.Equal(t, 1, root.Signed.Roles[ROOT].Threshold) + assert.NotEmpty(t, root.Signed.Roles[ROOT].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[ROOT].KeyIDs[0]) + assert.Equal(t, "roothash", root.Signed.Roles[ROOT].KeyIDs[0]) + + assert.Contains(t, root.Signed.Roles, SNAPSHOT) + assert.Equal(t, 1, root.Signed.Roles[SNAPSHOT].Threshold) + assert.NotEmpty(t, root.Signed.Roles[SNAPSHOT].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[SNAPSHOT].KeyIDs[0]) + assert.Equal(t, "snapshothash", root.Signed.Roles[SNAPSHOT].KeyIDs[0]) + + assert.Contains(t, root.Signed.Roles, TARGETS) + assert.Equal(t, 1, root.Signed.Roles[TARGETS].Threshold) + assert.NotEmpty(t, root.Signed.Roles[TARGETS].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[TARGETS].KeyIDs[0]) + assert.Equal(t, "targetshash", root.Signed.Roles[TARGETS].KeyIDs[0]) + + assert.Contains(t, root.Signed.Roles, TIMESTAMP) + assert.Equal(t, 1, root.Signed.Roles[TIMESTAMP].Threshold) + assert.NotEmpty(t, root.Signed.Roles[TIMESTAMP].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[TIMESTAMP].KeyIDs[0]) + assert.Equal(t, "timestamphash", root.Signed.Roles[TIMESTAMP].KeyIDs[0]) + + assert.Equal(t, int64(1), root.Signed.Version) + assert.NotEmpty(t, root.Signatures) + assert.Equal(t, "roothash", root.Signatures[0].KeyID) + data := []byte("some data") + h32 := sha256.Sum256(data) + h := h32[:] + assert.Equal(t, HexBytes(h), root.Signatures[0].Signature) +} + +func TestToByte(t *testing.T) { + rootBytesExpireStr := "2030-08-15T14:30:45.0000001Z" + rootBytesExpire, err := time.Parse(time.RFC3339, rootBytesExpireStr) + assert.NoError(t, err) + + root := Root(rootBytesExpire) + root.Signed.Keys["roothash"] = &Key{Type: "ed25519", Value: KeyVal{PublicKey: "pubrootval"}, Scheme: "ed25519"} + root.Signed.Keys["snapshothash"] = &Key{Type: "ed25519", Value: KeyVal{PublicKey: "pubsval"}, Scheme: "ed25519"} + root.Signed.Keys["targetshash"] = &Key{Type: "ed25519", Value: KeyVal{PublicKey: "pubtrval"}, Scheme: "ed25519"} + root.Signed.Keys["timestamphash"] = &Key{Type: "ed25519", Value: KeyVal{PublicKey: "pubtmval"}, Scheme: "ed25519"} + root.Signed.Roles[ROOT] = &Role{ + Threshold: 1, + KeyIDs: []string{"roothash"}, + } + root.Signed.Roles[SNAPSHOT] = &Role{ + Threshold: 1, + KeyIDs: []string{"snapshothash"}, + } + root.Signed.Roles[TARGETS] = &Role{ + Threshold: 1, + KeyIDs: []string{"targetshash"}, + } + root.Signed.Roles[TIMESTAMP] = &Role{ + Threshold: 1, + KeyIDs: []string{"timestamphash"}, + } + + data := []byte("some data") + h32 := sha256.Sum256(data) + h := h32[:] + hash := map[string]HexBytes{"ed25519": h} + root.Signatures = append(root.Signatures, Signature{KeyID: "roothash", Signature: hash["ed25519"]}) + rootBytes, err := root.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, string(testRootBytes), string(rootBytes)) +} + +func TestFromFile(t *testing.T) { + root := Root(fixedExpire) + _, err := root.FromFile(fmt.Sprintf("%s/1.root.json", TEST_REPOSITORY_DATA)) + assert.NoError(t, err) + + assert.Equal(t, fixedExpire, root.Signed.Expires) + assert.Equal(t, fixedExpire, root.Signed.Expires) + assert.Equal(t, ROOT, root.Signed.Type) + assert.True(t, root.Signed.ConsistentSnapshot) + assert.Equal(t, 4, len(root.Signed.Keys)) + + assert.Contains(t, root.Signed.Roles, ROOT) + assert.Equal(t, 1, root.Signed.Roles[ROOT].Threshold) + assert.NotEmpty(t, root.Signed.Roles[ROOT].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[ROOT].KeyIDs[0]) + assert.Equal(t, "d5fa855fce82db75ec64283e828cc90517df5edf5cdc57e7958a890d6556f5b7", root.Signed.Roles[ROOT].KeyIDs[0]) + + assert.Contains(t, root.Signed.Roles, SNAPSHOT) + assert.Equal(t, 1, root.Signed.Roles[SNAPSHOT].Threshold) + assert.NotEmpty(t, root.Signed.Roles[SNAPSHOT].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[SNAPSHOT].KeyIDs[0]) + assert.Equal(t, "700464ea12f4cb5f06a7512c75b73c0b6eeb2cd42854b085eed5b3c993607cba", root.Signed.Roles[SNAPSHOT].KeyIDs[0]) + + assert.Contains(t, root.Signed.Roles, TARGETS) + assert.Equal(t, 1, root.Signed.Roles[TARGETS].Threshold) + assert.NotEmpty(t, root.Signed.Roles[TARGETS].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[TARGETS].KeyIDs[0]) + assert.Equal(t, "409fb816e403e0c00646665eac21cb8adfab8e318272ca7589b2d1fc0bccb255", root.Signed.Roles[TARGETS].KeyIDs[0]) + + assert.Contains(t, root.Signed.Roles, TIMESTAMP) + assert.Equal(t, 1, root.Signed.Roles[TIMESTAMP].Threshold) + assert.NotEmpty(t, root.Signed.Roles[TIMESTAMP].KeyIDs) + assert.Contains(t, root.Signed.Keys, root.Signed.Roles[TIMESTAMP].KeyIDs[0]) + assert.Equal(t, "0a5842e65e9c8c428354f40708435de6793ac379a275effe40d6358be2de835c", root.Signed.Roles[TIMESTAMP].KeyIDs[0]) + + assert.Equal(t, SPECIFICATION_VERSION, root.Signed.SpecVersion) + assert.Contains(t, root.Signed.UnrecognizedFields, "test") + assert.Equal(t, "true", root.Signed.UnrecognizedFields["test"]) + + assert.Equal(t, int64(1), root.Signed.Version) + assert.NotEmpty(t, root.Signatures) + assert.Equal(t, "d5fa855fce82db75ec64283e828cc90517df5edf5cdc57e7958a890d6556f5b7", root.Signatures[0].KeyID) + +} + +func TestToFile(t *testing.T) { + tmp := os.TempDir() + tmpDir, err := os.MkdirTemp(tmp, "0750") + assert.NoError(t, err) + + fileName := fmt.Sprintf("%s/1.root.json", tmpDir) + assert.NoFileExists(t, fileName) + root, err := Root().FromBytes(testRootBytes) + assert.NoError(t, err) + + err = root.ToFile(fileName, false) + assert.NoError(t, err) + + assert.FileExists(t, fileName) + data, err := os.ReadFile(fileName) + assert.NoError(t, err) + assert.Equal(t, string(testRootBytes), string(data)) + + err = os.RemoveAll(tmpDir) + assert.NoError(t, err) + assert.NoFileExists(t, fileName) + +} + +func TestSign(t *testing.T) { + _, key, err := ed25519.GenerateKey(nil) + assert.NoError(t, err) + + signer, err := signature.LoadSigner(key, crypto.Hash(0)) + assert.NoError(t, err) + + root := Root(fixedExpire) + assert.Empty(t, root.Signatures) + sg, err := root.Sign(signer) + assert.NoError(t, err) + + assert.NotEmpty(t, root.Signatures) + assert.Equal(t, sg, &root.Signatures[0]) +} + +func TestVerifyDelegate(t *testing.T) { + root := Root(fixedExpire) + err := root.VerifyDelegate("test", root) + assert.EqualError(t, err, "value error: no delegation found for test") + + targets := Targets(fixedExpire) + err = targets.VerifyDelegate("test", targets) + assert.EqualError(t, err, "value error: no delegations found") + + key, _, err := ed25519.GenerateKey(nil) + assert.NoError(t, err) + + delegateeKey, _ := KeyFromPublicKey(key) + delegations := &Delegations{ + Keys: map[string]*Key{ + delegateeKey.ID(): delegateeKey, + }, + Roles: []DelegatedRole{ + { + Name: "test", + KeyIDs: []string{delegateeKey.ID()}, + }, + }, + } + targets.Signed.Delegations = delegations + err = targets.VerifyDelegate("test", root) + assert.NoError(t, err) + err = targets.VerifyDelegate("test", targets) + assert.NoError(t, err) + + err = targets.VerifyDelegate("non-existing", root) + assert.EqualError(t, err, "value error: no delegation found for non-existing") + err = targets.VerifyDelegate("non-existing", targets) + assert.EqualError(t, err, "value error: no delegation found for non-existing") + + targets.Signed.Delegations.Roles[0].Threshold = 1 + err = targets.VerifyDelegate("test", targets) + assert.Errorf(t, err, "Verifying test failed, not enough signatures, got %d, want %d", 0, 1) + + delegations.Keys["incorrectkey"] = delegations.Keys[delegateeKey.ID()] + delete(delegations.Keys, delegateeKey.ID()) + err = targets.VerifyDelegate("test", root) + assert.Errorf(t, err, "key with ID %s not found in test keyids", delegateeKey.ID()) + + timestamp := Timestamp(fixedExpire) + err = timestamp.VerifyDelegate("test", timestamp) + assert.EqualError(t, err, "type error: call is valid only on delegator metadata (should be either root or targets)") + + snapshot := Snapshot(fixedExpire) + err = snapshot.VerifyDelegate("test", snapshot) + assert.EqualError(t, err, "type error: call is valid only on delegator metadata (should be either root or targets)") +} + +func TestVerifyLengthHashesTargetFiles(t *testing.T) { + targetFiles := TargetFile() + targetFiles.Hashes = map[string]HexBytes{} + + data := []byte{} + err := targetFiles.VerifyLengthHashes(data) + assert.NoError(t, err) + + data = []byte("some data") + err = targetFiles.VerifyLengthHashes(data) + assert.Error(t, err, "length/hash verification error: length verification failed - expected 0, got 9") + + h32 := sha256.Sum256(data) + h := h32[:] + targetFiles.Hashes["sha256"] = h + targetFiles.Length = int64(len(data)) + err = targetFiles.VerifyLengthHashes(data) + assert.NoError(t, err) + + targetFiles.Hashes = map[string]HexBytes{"unknownAlg": data} + err = targetFiles.VerifyLengthHashes(data) + assert.Error(t, err, "length/hash verification error: hash verification failed - unknown hashing algorithm - unknownArg") + + targetFiles.Hashes = map[string]HexBytes{"sha256": data} + err = targetFiles.VerifyLengthHashes(data) + assert.Error(t, err, "length/hash verification error: hash verification failed - mismatch for algorithm sha256") +} + +func TestVerifyLengthHashesMetaFiles(t *testing.T) { + version := int64(0) + metaFile := MetaFile(version) + data := []byte("some data") + metaFile.Hashes = map[string]HexBytes{"unknownAlg": data} + err := metaFile.VerifyLengthHashes(data) + assert.Error(t, err, "length/hash verification error: hash verification failed - unknown hashing algorithm - unknownArg") + + metaFile.Hashes = map[string]HexBytes{"sha256": data} + err = metaFile.VerifyLengthHashes(data) + assert.Error(t, err, "length/hash verification error: hash verification failed - mismatch for algorithm sha256") + + h32 := sha256.Sum256(data) + h := h32[:] + metaFile.Hashes = map[string]HexBytes{"sha256": h} + err = metaFile.VerifyLengthHashes(data) + assert.NoError(t, err) + + incorrectData := []byte("another data") + err = metaFile.VerifyLengthHashes(incorrectData) + assert.Error(t, err, "length/hash verification error: length verification failed - expected 0, got 9") } From 90736f6f7f8e5d4d77d9354d0d61f011f61af910 Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Thu, 15 Jun 2023 21:06:19 +0300 Subject: [PATCH 05/11] Add metadata api tests This change implements api unit tests for metadata with the same logic as in python-tuf Signed-off-by: Ivana Atanasova --- metadata/metadata_api_test.go | 274 ++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 metadata/metadata_api_test.go diff --git a/metadata/metadata_api_test.go b/metadata/metadata_api_test.go new file mode 100644 index 00000000..c604d27b --- /dev/null +++ b/metadata/metadata_api_test.go @@ -0,0 +1,274 @@ +// Copyright 2023 VMware, Inc. +// +// This product is licensed to you under the BSD-2 license (the "License"). +// You may not use this product except in compliance with the BSD-2 License. +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to +// the terms and conditions of the subcomponent's license, as noted in the +// LICENSE file. +// +// SPDX-License-Identifier: BSD-2-Clause + +package metadata + +import ( + "bytes" + "encoding/json" + "fmt" + "testing" + + simulator "github.com/rdimitrov/go-tuf-metadata/testutils/simulators" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +func TestMain(m *testing.M) { + + err := simulator.SetupTestDirs() + defer simulator.Cleanup() + + if err != nil { + log.Fatalf("failed to setup test dirs: %v", err) + } + m.Run() +} + +func TestGenericRead(t *testing.T) { + // Assert that it chokes correctly on an unknown metadata type + badMetadata := "{\"signed\": {\"_type\": \"bad-metadata\"}}" + _, err := Root().FromBytes([]byte(badMetadata)) + assert.ErrorContains(t, err, "expected metadata type root, got - bad-metadata") + _, err = Snapshot().FromBytes([]byte(badMetadata)) + assert.ErrorContains(t, err, "expected metadata type snapshot, got - bad-metadata") + _, err = Targets().FromBytes([]byte(badMetadata)) + assert.ErrorContains(t, err, "expected metadata type targets, got - bad-metadata") + _, err = Timestamp().FromBytes([]byte(badMetadata)) + assert.ErrorContains(t, err, "expected metadata type timestamp, got - bad-metadata") + + badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", simulator.RepoDir) + err = simulator.CreateFile(badMetadataPath, []byte(badMetadata)) + assert.NoError(t, err) + assert.FileExists(t, badMetadataPath) + + _, err = Root().FromFile(badMetadataPath) + assert.ErrorContains(t, err, "expected metadata type root, got - bad-metadata") + _, err = Snapshot().FromFile(badMetadataPath) + assert.ErrorContains(t, err, "expected metadata type snapshot, got - bad-metadata") + _, err = Targets().FromFile(badMetadataPath) + assert.ErrorContains(t, err, "expected metadata type targets, got - bad-metadata") + _, err = Timestamp().FromFile(badMetadataPath) + assert.ErrorContains(t, err, "expected metadata type timestamp, got - bad-metadata") + + err = simulator.DeleteFile(badMetadataPath) + assert.NoError(t, err) + assert.NoFileExists(t, badMetadataPath) +} + +func TestMDReadWriteFileExceptions(t *testing.T) { + // Test writing to a file with bad filename + badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", simulator.RepoDir) + _, err := Root().FromFile(badMetadataPath) + assert.ErrorContains(t, err, fmt.Sprintf("open %s: no such file or directory", badMetadataPath)) + + // Test serializing to a file with bad filename + root, err := Root().FromFile(fmt.Sprintf("%s/root.json", simulator.RepoDir)) + assert.NoError(t, err) + err = root.ToFile("", false) + assert.ErrorContains(t, err, "no such file or directory") +} + +func TestRootReadWriteReadCompare(t *testing.T) { + path1 := simulator.RepoDir + "/root.json" + root1, err := Root().FromFile(path1) + assert.NoError(t, err) + + path2 := path1 + ".tmp" + err = root1.ToFile(path2, false) + assert.NoError(t, err) + + root2, err := Root().FromFile(path2) + assert.NoError(t, err) + + bytes1, err := root1.ToBytes(false) + assert.NoError(t, err) + bytes2, err := root2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, bytes1, bytes2) + + err = simulator.DeleteFile(path2) + assert.NoError(t, err) +} + +func TestSnapshotReadWriteReadCompare(t *testing.T) { + path1 := simulator.RepoDir + "/snapshot.json" + snaphot1, err := Snapshot().FromFile(path1) + assert.NoError(t, err) + + path2 := path1 + ".tmp" + err = snaphot1.ToFile(path2, false) + assert.NoError(t, err) + + snapshot2, err := Snapshot().FromFile(path2) + assert.NoError(t, err) + + bytes1, err := snaphot1.ToBytes(false) + assert.NoError(t, err) + bytes2, err := snapshot2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, bytes1, bytes2) + + err = simulator.DeleteFile(path2) + assert.NoError(t, err) +} + +func TestTargetsReadWriteReadCompare(t *testing.T) { + path1 := simulator.RepoDir + "/targets.json" + targets1, err := Targets().FromFile(path1) + assert.NoError(t, err) + + path2 := path1 + ".tmp" + err = targets1.ToFile(path2, false) + assert.NoError(t, err) + + targets2, err := Targets().FromFile(path2) + assert.NoError(t, err) + + bytes1, err := targets1.ToBytes(false) + assert.NoError(t, err) + bytes2, err := targets2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, bytes1, bytes2) + + err = simulator.DeleteFile(path2) + assert.NoError(t, err) +} + +func TestTimestampReadWriteReadCompare(t *testing.T) { + path1 := simulator.RepoDir + "/timestamp.json" + timestamp1, err := Timestamp().FromFile(path1) + assert.NoError(t, err) + + path2 := path1 + ".tmp" + err = timestamp1.ToFile(path2, false) + assert.NoError(t, err) + + timestamp2, err := Timestamp().FromFile(path2) + assert.NoError(t, err) + + bytes1, err := timestamp1.ToBytes(false) + assert.NoError(t, err) + bytes2, err := timestamp2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, bytes1, bytes2) + + err = simulator.DeleteFile(path2) + assert.NoError(t, err) +} + +func TestSerializeAndValidate(t *testing.T) { + // Assert that by changing one required attribute validation will fail. + root, err := Root().FromFile(simulator.RepoDir + "/root.json") + assert.NoError(t, err) + root.Signed.Version = 0 + + _, err = root.ToBytes(false) + // TODO: refering to python-tuf, this should fail + assert.NoError(t, err) +} + +func TrimBytes(data []byte) ([]byte, error) { + buffer := new(bytes.Buffer) + err := json.Compact(buffer, data) + if err != nil { + log.Debugf("failed to trim bytes: %v", err) + return data, err + } + data = buffer.Bytes() + return data, nil +} + +func TestToFromBytes(t *testing.T) { + // ROOT + data, err := simulator.ReadFile(simulator.RepoDir + "/root.json") + assert.NoError(t, err) + data, err = TrimBytes(data) + assert.NoError(t, err) + root, err := Root().FromBytes(data) + assert.NoError(t, err) + + // Comparate that from_bytes/to_bytes doesn't change the content + // for two cases for the serializer: noncompact and compact. + + // Case 1: test noncompact by overriding the default serializer. + rootBytes, err := root.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, data, rootBytes) + + // Case 2: test compact by using the default serializer. + root2, err := Root().FromBytes(rootBytes) + assert.NoError(t, err) + root2Bytes, err := root2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, rootBytes, root2Bytes) + + // SNAPSHOT + data, err = simulator.ReadFile(simulator.RepoDir + "/snapshot.json") + assert.NoError(t, err) + data, err = TrimBytes(data) + assert.NoError(t, err) + snapshot, err := Snapshot().FromBytes(data) + assert.NoError(t, err) + + // Case 1: test noncompact by overriding the default serializer. + snapshotBytes, err := snapshot.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, string(data), string(snapshotBytes)) + + // Case 2: test compact by using the default serializer. + snapshot2, err := Snapshot().FromBytes(snapshotBytes) + assert.NoError(t, err) + snapshot2Bytes, err := snapshot2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, string(snapshotBytes), string(snapshot2Bytes)) + + // TARGETS + data, err = simulator.ReadFile(simulator.RepoDir + "/targets.json") + assert.NoError(t, err) + data, err = TrimBytes(data) + assert.NoError(t, err) + targets, err := Targets().FromBytes(data) + assert.NoError(t, err) + + // Case 1: test noncompact by overriding the default serializer. + targetsBytes, err := targets.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, string(data), string(targetsBytes)) + + // Case 2: test compact by using the default serializer. + targets2, err := Targets().FromBytes(targetsBytes) + assert.NoError(t, err) + targets2Bytes, err := targets2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, string(targetsBytes), string(targets2Bytes)) + + // TIMESTAMP + data, err = simulator.ReadFile(simulator.RepoDir + "/timestamp.json") + assert.NoError(t, err) + data, err = TrimBytes(data) + assert.NoError(t, err) + timestamp, err := Timestamp().FromBytes(data) + assert.NoError(t, err) + + // Case 1: test noncompact by overriding the default serializer. + timestampBytes, err := timestamp.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, string(data), string(timestampBytes)) + + // Case 2: test compact by using the default serializer. + timestamp2, err := Timestamp().FromBytes(timestampBytes) + assert.NoError(t, err) + timestamp2Bytes, err := timestamp2.ToBytes(false) + assert.NoError(t, err) + assert.Equal(t, string(timestampBytes), string(timestamp2Bytes)) + +} From fc2612112fbed8c0a255051d038475c83d10b3fe Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Fri, 16 Jun 2023 14:45:50 +0300 Subject: [PATCH 06/11] Fix go linter in test simulators This change fixes go linter error of not checking errors returned by methods in the file system and test client simulators Signed-off-by: Ivana Atanasova --- testutils/simulators/file_system.go | 5 ++++- testutils/simulators/test_client.go | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/testutils/simulators/file_system.go b/testutils/simulators/file_system.go index e4ec0b9c..bdcb83a1 100644 --- a/testutils/simulators/file_system.go +++ b/testutils/simulators/file_system.go @@ -34,7 +34,10 @@ func (*osFS) Mkdir(name string) error { } func (*osFS) Copy(fromPath string, toPath string) error { - os.MkdirAll(toPath, 0750) + err := os.MkdirAll(toPath, 0750) + if err != nil { + log.Debugf("failed to create directory %s: %v", toPath, err) + } files, err := os.ReadDir(fromPath) if err != nil { log.Debugf("failed to read path %s: %v", fromPath, err) diff --git a/testutils/simulators/test_client.go b/testutils/simulators/test_client.go index 34a96dcb..909e43fd 100644 --- a/testutils/simulators/test_client.go +++ b/testutils/simulators/test_client.go @@ -32,23 +32,32 @@ func SetupTestDirs() error { log.Fatal("failed to create temporary directory: ", err) return err } - fmt.Println(TempDir) RepoDir = fmt.Sprintf("%s/repository_data/repository", TempDir) - fs.Mkdir(RepoDir + "/metadata") absPath, err := filepath.Abs("../testutils/repository_data/repository/metadata") if err != nil { log.Debugf("failed to get absolute path: %v", err) } - fs.Copy(absPath, RepoDir) + err = fs.Copy(absPath, RepoDir) + if err != nil { + log.Debugf("failed to copy metadata to %s: %v", RepoDir, err) + return err + } KeystoreDir = fmt.Sprintf("%s/keystore", TempDir) - fs.Mkdir(KeystoreDir) + err = fs.Mkdir(KeystoreDir) + if err != nil { + log.Debugf("failed to create keystore dir %s: %v", KeystoreDir, err) + } absPath, err = filepath.Abs("../testutils/repository_data/keystore") if err != nil { log.Debugf("failed to get absolute path: %v", err) } - fs.Copy(absPath, KeystoreDir) + err = fs.Copy(absPath, KeystoreDir) + if err != nil { + log.Debugf("failed to copy keystore to %s: %v", KeystoreDir, err) + return err + } // TODO: load keys to keystore map @@ -57,5 +66,8 @@ func SetupTestDirs() error { func Cleanup() { log.Printf("cleaning temporary directory: %s\n", TempDir) - fs.RemoveAll(TempDir) + err := fs.RemoveAll(TempDir) + if err != nil { + log.Fatalf("failed to cleanup test directories: %v", err) + } } From 436fd769e4fd48594c73fcd98d494a95472562bc Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Fri, 30 Jun 2023 10:26:32 +0300 Subject: [PATCH 07/11] Create clean test metadata repository As the `signature` package allows loading keys from RSA PEM files only, the keys and roles from the python-tuf implementation are not suitable for the current implementation. This is why a clean repo is created with new keys in the appropriate format Signed-off-by: Ivana Atanasova --- testutils/repository_data/keystore/root_key | 57 ++++--------- .../repository_data/keystore/root_key.pub | 15 ++-- .../repository_data/keystore/snapshot_key | 16 +++- .../repository_data/keystore/snapshot_key.pub | 3 +- .../repository_data/keystore/targets_key | 16 +++- .../repository_data/keystore/targets_key.pub | 2 +- .../repository_data/keystore/timestamp_key | 16 +++- .../keystore/timestamp_key.pub | 2 +- .../repository/metadata/1.root.json | 14 ++-- .../repository/metadata/root.json | 72 +++++++---------- .../repository/metadata/snapshot.json | 40 ++++------ .../repository/metadata/targets.json | 79 +++++-------------- .../repository/metadata/timestamp.json | 38 ++++----- 13 files changed, 158 insertions(+), 212 deletions(-) diff --git a/testutils/repository_data/keystore/root_key b/testutils/repository_data/keystore/root_key index 1b8fb145..53e754d2 100644 --- a/testutils/repository_data/keystore/root_key +++ b/testutils/repository_data/keystore/root_key @@ -1,42 +1,15 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIHbTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIsnvMDGLfuE8CAggA -MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBN6jE1eBpMFrFfAs0FkzHQBIIH -EAacUao28rDMs/rL1H4hrWN6OqkcAzjMG/dNDDiLtljpHsYHYWg417cz4eVsWVw7 -SzP005D5qu78oBa35Yg22zW3vlHS1RDlPKFpYrFliwgaWaxVx7CrKhGXq8CeoCnS -aymN43o493TExHUOGgjTU7eLPXk8eVZ5aO+ml+i/YyPldrEwcghsBDD27zwXOgZk -qwFoCxCWVUCRcywaTGGvRQ13GVcLYlj+CjTzp2ctXzcWhGK77kPhtVFXpGO00vVn -7i2kyZm8tLXXFJ+fAMm3OCyyIUnFlf2KuYRECksUvGbscgIH/W2O6qvq7klgappB -xiyI8dlBeOboxtdbnqoSkodac0pfY8a7b0SIw5H6U/2hiNEQx2o/gFMFq8OklwiW -gO3PCjtG/bXFYqBjzBtBdAQ77UEv3pbeZNReLx7gCn7YIyLQ5ltqG2Kmbp8pb08w -hFJm6CcHkBP4GkfzNGtagJCbqX0ys5yG2DxqGZAGPynydwr3EbrvF8UToAaVpgR4 -7RqVk/uZf48UM6M/I8Q0aHz1fja9pwY7H/syyBs2R3Pn98O2HxZ8futqxefCImbs -DL6cd+VCFjmgsIQBYku2eqYEm98MLWHsiLbNPnyjgmrMElBVWNBlYsYXxqgL+lR1 -fvNBZlYCr7ZthfD+DtxmRU3rApl2Hi22x5IwI7N/4B3/+nRKJLRoc1gW+kekE91j -PRB30iLR+a5FkFA0u6ymRw7TvYY2u8Y8zbWwhC1rtCTCDcFAOGMGiDxSwbJX7e9y -cjGPZH+9daNEH03B51MlGwPee511ehtMa1RhWWCGsMsWzeOpIqy1yzPxGkAO0+Wo -ReNgtlOcjKanW6gdOpiGAeZRKBBYKZhAj8ogs958ZWYRVpNUzNs8ihMRuH4PSJzE -BrJFqgvk+YXwZFLw2ugZmjPRdjbCJOVdh25xAMy+hrlL4ZwWT50WHYsfGDUeM/kq -uwidpU94Xi4C5MJww0Z7grztbmUqRqNGiPyqGakgB7LtEwPICOaxeHSYOu+PTklF -0Sl2aEH7VuptfVknndd8AX0ozMrSFe0jh5I5CA+Bu315EJfHgHiYB31VpKKpY6Bn -Naeb2rH+CpajLNC7ULcDRpHRZNkolX6nHLf63PGPhD6x1HdJWlfQAXk7+mNFtVZ5 -ugXD/6Hei9w0JYAbPr0Up2tw2KPIRW75CFJdpIwqTdV20ZfP4kbUZOfOK9ltWyB1 -2q6OXliEfvzRYXI8TbUfZ6RpgH6j8VWia/ER/q4O0cKoQ5UfP3RgKil2Jz3QJTYe -E6DVJkv5NtSRK7ZkdtI8SZCkOQ0Rhz0NKmQhDlftoQOYWmLkPJenQVNxra6hOO2l -6cZ2e1AVv+8csR/22Qipve8IRfqLsH48dKP3cXZSM/7CaF/q1Wgkc+nZBOLVpK5P -Q6+bCljxtdlbR5bzTrbz2ELorGCH3bNg+O73MD27wtNbkb2ZmleVXc5WU733CKr1 -8edMWaAtWMkLNUlCJ8bnBOGb2sIy9PXzEWn1kECDhQSgcSaBnIglU03z/5/9HLpc -8lpC0yUTIhwX0zr8G0ZpirIcfvjNhq4qksR8bahc8eNkf6Rn3sB4E8uSv0UbxG/V -OibWXabyb5t5J261+WWmalz02Q4iQso0YIUOZBiKAlY4mIf2sWQX4rFSWconYBb5 -me5+BBVfJN7WO0RGG8aliqj8op/BkwhS2P1cWKntIm7DWKr5QyU/oj044ZpxkwZd -TL5n+puYkijgUkcvab+ew9x+f3speWdv2a9Zuk3mKEO4TcKnchE/4M/mIzoX/bmI -KLsZ2c7WUySfGzFBEZUY6NUR3bkehIDOY7fCnS0Dz7rSbImNVsMp8QbgANvK6YL8 -M6MJfZKWh6VEBm2athFV8Rc+q1Bf0VMO5+/8ay+GSFN+EIbPZZOwmNpzlIg6m0LS -ix+7/k1H3vjHwhxRa3g/2vqoY/mwdvjb1+bMsejygGV0vF57R5Zlm842ZWPaVQYz -T5gElaP+BXDIo7pkXMOrvr9oKkDFWPhhKpfzm94i5QUpYGJIbr811e4tQzh9WfrX -nnaARPhUrE+Yhy5ghWMDwA8So2FoUlCzS9zAW5cgMPdwvn/zraY0HCp8wGW/yNl6 -jhwSvmUa2SnQkPuR977lkWodLOU9mwOnvZqplmhprh4w+znoPcuTNM5XQ7Rxulfx -ZOJZ7NjLr3t2gY2Ni4Su961GcG9/1qgb/gbh+epzpIWaMSfJhXwBv/TmDppg1IB/ -q1Y2ICtZX0V6/szszPsPpBcqRpMAa6T12pL/J6OVYcnSrX6lzY8uVzM4Va1M/Fwn -C45VwvBK0StZY2T+CWdAoG20wA9IJhSr8xajCxR1UNsNgrQ84dJN6KduURbNmMTM -m5fryjMFAoykt+cz1TOq7G3sFLslYkWH8DP1mdknC1uC ------END ENCRYPTED PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDydf/VEpxBOCDoxpM6IVhq9i67P9BiVv2zwZSUO/M0RTToAvFv +NgDKXwtnp8LyjVk++wMA1aceMa+pS7vYrKvPIJa7WIT+mwy86/fIdnllJDMw5tmL +r2mE3oBMxOhpEiD2tO+liGacklFNk6nHHorX9S91iqpdRVa3zJw5ALvLdwIDAQAB +AoGBAJlhwoUVb9nmWxNGw86LV7bapDd6qCX96CL2PDsGLdWMTmrTqc5zuE5NkBZz +z2THvISWIJE/l6gHQJv1uBDbMxfquhK40k+GfE/fApVODN8KeBLLRUzYyHNz7KwW +aNF3jY8AbO4HzWpdaFYce5r+YqlWZoaVPR9i6LCW3sZXALyRAkEA/lSVaT0azp55 +2GI4Gn+EQQFqFJWEbNwJ8i3FZ4aG+/gnw2WmxJr+2nQcUlLb2cpQCCcMyWxvCfLK ++DapvvgZXwJBAPQNd+liOrKKd1gPR3S6y+D4h1ewj8ii1MHzRtAsCKCRG/e+v+hC +xp77Rc/qtZXKvVTGrccnKqCVAvG7F15rzOkCQQDCswgKn6+0+5c1ssNWbcZWaXnH +NktBdxXaI3Ya8d7GaEwwhtIrcqilnfvMfgg2a23nP9XHIU7EI+2EJXy/aHkrAkBH +wH30u9COFW+pEDTt+M1gQzFncp2TW2w56ZB0O739lywl1osNejRzIWURD+x7MbQg +bJlC6Bz8QVMwRtVECWWhAkAflD6eIJeceDhVHClHB/QwmF8mwR1o63RN7ZFlgel1 +kwMt6bPZZ1cyrRoj6Cdi4pyqBssDBuQmbBLWyYuijIwz +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key.pub b/testutils/repository_data/keystore/root_key.pub index 11cc245f..095c0663 100644 --- a/testutils/repository_data/keystore/root_key.pub +++ b/testutils/repository_data/keystore/root_key.pub @@ -1,11 +1,6 @@ -----BEGIN PUBLIC KEY----- -MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe -PkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i -xmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity -fQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa -ndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc -MdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV -z94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y -R47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA -a82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE= ------END PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDydf/VEpxBOCDoxpM6IVhq9i67 +P9BiVv2zwZSUO/M0RTToAvFvNgDKXwtnp8LyjVk++wMA1aceMa+pS7vYrKvPIJa7 +WIT+mwy86/fIdnllJDMw5tmLr2mE3oBMxOhpEiD2tO+liGacklFNk6nHHorX9S91 +iqpdRVa3zJw5ALvLdwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/testutils/repository_data/keystore/snapshot_key b/testutils/repository_data/keystore/snapshot_key index 08c954fd..cac57dd6 100644 --- a/testutils/repository_data/keystore/snapshot_key +++ b/testutils/repository_data/keystore/snapshot_key @@ -1 +1,15 @@ -a87b80b8a0d39b919b9638181e7b274e@@@@100000@@@@132edd670981aaf1980673966266174d944d735eb5b0b7ec83ed97da5c212249@@@@bd08ae9898ac5f81fc14e418e9790f9b@@@@399250c9aad40035e0acff48db59697bc3cf33d55b52aa272246addeaaf318d931d3a72964f0c84eccf5b89279b8233685330ad884f7b39bf369553133b985f9396bd5e24cb8e343643923022565a645e188a1165e427aedc389cca821d6a93cb2d8d16cea8ffeb56469bcb9f2f66e03d581a2ea37da271980dd02b84717fe475e13a305b4ae714c11c94f6711c744bb291a146d7419474584bad4be152d0299273c1fad6cd95232a4bf07f39c16da7f4d13201a88fad822cb328008e8a2762baf974b5d5080451751fb8ef53a01ca734157be78b3eb13c6270e4e98b138c78388360e7f558389871b7a32b4d5572626b3112264a0b56dbbb1138c9765872a71dd4e7d31006c2e690f5ede608ce633ad94ebb7d1ddec1a7eac2168fc5d36efe590c4c2059c6f3bcf75ab63474eede3ce4fdc93c6564058b14a0fa9bf3cb6d58c53315b406409ee4aeb18abe072734df0 \ No newline at end of file +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCPQoHresXRRRGoinN3bNn+BI23KolXdXLGqYkTvr9AjemUQJxb +qmvZXHboQMAYw8OuBrRNt5Fz20wjsrJwOBEU5U3nHSJI4zYPGckYci0/0Eo2Kjws +5BmIj38qgIfhsH4zyZ4FZZ+GLRn+W3i3wl6SfRMC/HCg0DDwi75faC0vGQIDAQAB +AoGAbPFYt2hf8qqhqRfQgysmA4QW+QnB895+8BCRC5DtA/xnerQ/s33AEkW8rxY+ +fxawQjEbAFbup7pHBoaoJ6qbYbKDBSGgZFSEbh40nriX1V0oYb9E+BCAFHE+42Rj +WYYNxXRp7LGoUQqisTsfoR1bvmrLC+9I/tDArHuMudm1slkCQQDOVn9AKTcaBGuQ +Y+JQqoRmi9eMN6XztKIAKQ+P/57BofwlKJDFnwttsvMxRud6rvN1FCnCDM638HNb +I0JDY0JXAkEAsb10uNV+SaWsHJOxfHzwK+uZJV1SkYzpBMizUREHuIyKT4MfpYNw +kn00KpyCvhIp6buwNyYo76TssejYN86UDwJAGi3ZSU+xYQisiQ5TOX7Y+5XEjFLH +KGuDnleXVOLOxqyBrElATQKH1aw9tMPVPLiTxQgA4FD1rVrBmA+aKaifUwJALBp8 +yhh/u7qWWIj1c5R07BEL8U+U23UBpSRACo+VQN/uuggpZCKXXmIe/avUbWGIcO0X +rreTVNOxv/utGzvxVQJBAL7Kpqt9d50SL1ndLr2EdqGw8ZB/B2dKMlZf7AWwbk0k +HHdvWfSDYhtvGo3ilLibHLesE/Tq1fm/2aEOds95/Eo= +-----END RSA PRIVATE KEY----- diff --git a/testutils/repository_data/keystore/snapshot_key.pub b/testutils/repository_data/keystore/snapshot_key.pub index d08bb848..a0df8cf1 100644 --- a/testutils/repository_data/keystore/snapshot_key.pub +++ b/testutils/repository_data/keystore/snapshot_key.pub @@ -1 +1,2 @@ -{"keyval": {"public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file +{"keyval": {"public": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCG5DWxCcw4FW2G21RwTmuR7gdkv+ZrjZVOx0KsvJc/51QBxo/Y9xPVeoFF7YrhE8EV6A6b0qsLufIo1E63sQ6kjLOPfIMjag6dYPlmEyGcbxNDokv2elxZk7jS98iBQLxEmJLicrdERmxC2t2OOEQ6ELi5dt+C13QvNJFg4+OaTwIDAQAB"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} + diff --git a/testutils/repository_data/keystore/targets_key b/testutils/repository_data/keystore/targets_key index c3883ec3..800dae9a 100644 --- a/testutils/repository_data/keystore/targets_key +++ b/testutils/repository_data/keystore/targets_key @@ -1 +1,15 @@ -a5a903322888df0bf8275b215f2044fe@@@@100000@@@@5f6b803652cb6d5bce4e07b1482597adb96d06c2efa3393abdcc0425f70be692@@@@0664811967e2f413927ce51a7f43a80e@@@@cf1dccd034400195c667c064198ef25555f3f94bf9cf77fbe300246618e557ad0efa775ef90bd46c842696c45d14033199860b2214c3641e87889a41171f8a2c763d004681b66b462ff34599e8d9da87f5642d2a015b75d3f601d198e0467fa4bc28f65c76260585e0cce71281f67a8053116f0f06883155f602811071b56bf75bf54daae5968b0a31cf829510f3c52c0eeb8f1c6bb8b8cb0c3edb4c6c2dd9d13bee00c5d63c3f98e0904eebb609864f4ab4fcc2c17bba8fd36aa06bc96bc1922eb10557051a674acf2cb01ff3efb7d55411df6915bbc49a095ff4472dc441e2765244f801d0df07b754c952d039f39b4530930a14be42cb2041f22eeb306b12f12158fcd2beb033db1be21f5a6ab72335cf16dfbd19cbf39c00b0a571d2b0e25df032be53a49a7a70ecebebb441d327c638cf31804381afaf809cd1c75f9070e83240fbaaa87bea0799404ece788862 \ No newline at end of file +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCjm6HPktvTGsygQ8Gvmu+zydTNe1zqoxLxV7mVRbmsCI4kn7JT +Hc4fmWZwvo7f/Wbto6Xj5HqGJFSlYIGZuTwZqPg3w8wqv8cuPxbmsFSxMoHfzBBI +uJe0FlwXFysojbdhrSUqNL84tlwTFXEhePYrpTNMDn+9T55B0WJYT/VPxwIDAQAB +AoGANYaYRLHWS1WMNq6UMmBtJZPVlDhU6MrbSqwZojWCjj7qSh8ZF0o8AmiMdDxT +wAJGZ17PyiQY1cQTEVvmaqWIfJKvipAcTvkiXFrAxeIf/HYIVfCP9UB8RqhJufsc +XzDQyvZTmJdatHfKe2JV+q42GrsN4VN61wFEed3NuF8NGjECQQDSA5b+N1wMn5X4 +G5fxPYjhlwQmK3tlBHIPIVcVAsGOxU9Ry55xLQ8LpfKwJZIt2+LvgBIXf4DZY2u6 +GEnyR7epAkEAx267l7XX+9Dh8bHPluQSgH/tDrCp1hUNmyV4XzZCwavI/FaucANa +h8ChpUOSZTq5mR76YaUL7O3Sx8N7L/2x7wJAZDvgYf6sCT5VhnAtCa+T2A+KpGkW +YLVJdt0zwcxp8ylK3UAwo9Wcm7Oda+LSrN6IpkRa3io1pguki9Ix4NfH2QJATsXA +NxZOb1p8RFk1Y6ZGYJcm7Wx+SN8b9rIAL6thBtpxkqoyUHAirAg8UOi1xGJDuOVx +hGwKn9T4MotV9wi/5QJAB+1/2TaUMKjyL5Ca8Fh5SMigrwHp8SnX2vl7HV4hiBXi +0FaVxMPGH94tuFqHQ+q53tiTT1cp6YwcMMgpezTRRA== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/testutils/repository_data/keystore/targets_key.pub b/testutils/repository_data/keystore/targets_key.pub index e859eb22..21fae67c 100644 --- a/testutils/repository_data/keystore/targets_key.pub +++ b/testutils/repository_data/keystore/targets_key.pub @@ -1 +1 @@ -{"keyval": {"public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file +{"keyval": {"public": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjm6HPktvTGsygQ8Gvmu+zydTNe1zqoxLxV7mVRbmsCI4kn7JTHc4fmWZwvo7f/Wbto6Xj5HqGJFSlYIGZuTwZqPg3w8wqv8cuPxbmsFSxMoHfzBBIuJe0FlwXFysojbdhrSUqNL84tlwTFXEhePYrpTNMDn+9T55B0WJYT/VPxwIDAQAB"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file diff --git a/testutils/repository_data/keystore/timestamp_key b/testutils/repository_data/keystore/timestamp_key index ca825790..4d5bbddb 100644 --- a/testutils/repository_data/keystore/timestamp_key +++ b/testutils/repository_data/keystore/timestamp_key @@ -1 +1,15 @@ -677a42cd6c1df08d0c6156ae356c2875@@@@100000@@@@3850dbcf2973b80044912d630f05039df64775b63d1cf43e750d3cd8a457c64f@@@@bf01961c386d9fefb4b29db7f6ef0c7f@@@@96d37abafb902f821134d2034855d23b78c82e5b768b092fcf0d3b6b28a74734877a5014b26e5fed289d24f7cf6b393445c3231554c5b6d9711192cf9bd2fb7490497d7d76c619a0cfc70abae026b5068fb66db0138b04f890917daad66ca1f7baabdcbb5282e46a2f1c6ff2e8c241ff16ef31e918ca1387a15bc2ceadb2f75ce68fcff08186b5b901a499efe1f674319b503ff8b6fc004b71d0ecb94253f38c58349ab749e72f492e541e7504d25a0bfe791f53eb95c4524431b0f952fc3d7c7204a2a4aab44d33fe09cb36b337339e2a004bf15dfd925b63930905972749441a0c6e50ec9b1748a4cfbacf10b402ebd9c0074fcb38d236fd3146f60232862b0501e8e6caa9f81c223de03ba7b25a1d4bc2d031901dc445f25ce302d2189b8b8de443bc6f562f941b55595655193ab6b84c1ec2302ca056c70e8efb1cad909c50e82e0b7da9ad64202d149e4e837409 \ No newline at end of file +-----BEGIN RSA PRIVATE KEY----- +MIICWgIBAAKBgHXjYnWGuCIOh5T3XGmgG/RsXWHPTbyu7OImP6O+uHg8hui8C1nY +/mcJdFdxqgl1vKEco/Nwebh2T8L6XbNfcgV9VVstWpeCalZYWi55lZSLe9KixQIA +yg15rNdhN9pcD3OuLmFvslgTx+dTbZ3ZoYMbcb4C5yqvqzcOoCTQMeWbAgMBAAEC +gYAMlDvAUKS7NZOwCIj62FPDTADW2/juhjfOlcg6n7ItWkAG+3G2n5ndwruATSeY +pNCA3H5+DmVeknlGU9LFvgx7dhJMw3WSkq7rImOGbwLN1jCVfwKP0AEEqb7GrtCU +a9lvm2ZFvKj+2VVFS2yifeluDG1Xm10ygq+RDd2lL2g6eQJBAMZrMTUwxWT/Cc0j +Yi7CFPl9V8GkYzLCKRQGR3x4QiNuXpNtQ3D+ivxHieBMEtw6M244PMDC+GpLxAfc +DtiGEl8CQQCYGXeycwkgn2YfH3w1/Mw6TWsdv4rVLPOieiQPrhZbVsBc6NT24MYW +b3c7osW5ypf7lo+xU8E6ylFUyeeVSk5FAkADTAqwSJQvHnHKP9lEz6LLloKbzCB9 +2m4WUBhmABWRQyc9Keah/QjQMlwfJwR1Nl5eaX7Q8Sxxj7q9KrHwdSHfAkAS1yTC +kAlTZytJM6c5MMVDe4+HMdDKszTCrYqF/rR6P/a4C4dFxXYEFW6ZjoIbj4LgAThv +aMaIt8L3U8NB9OBZAkA3ke4kilnVnjEyB9ibJ/SbDiUgh7e7M/XDbNQuXwSipFft +keBYEwL4Njms9uwMT4Gl59HyQls7BE2XEoiFjsY1 +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/testutils/repository_data/keystore/timestamp_key.pub b/testutils/repository_data/keystore/timestamp_key.pub index 69ba7ded..6edc5c95 100644 --- a/testutils/repository_data/keystore/timestamp_key.pub +++ b/testutils/repository_data/keystore/timestamp_key.pub @@ -1 +1 @@ -{"keyval": {"public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4"}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file +{"keyval": {"public": "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHXjYnWGuCIOh5T3XGmgG/RsXWHPTbyu7OImP6O+uHg8hui8C1nY/mcJdFdxqgl1vKEco/Nwebh2T8L6XbNfcgV9VVstWpeCalZYWi55lZSLe9KixQIAyg15rNdhN9pcD3OuLmFvslgTx+dTbZ3ZoYMbcb4C5yqvqzcOoCTQMeWbAgMBAAE="}, "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"]} \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/1.root.json b/testutils/repository_data/repository/metadata/1.root.json index 9adb68b3..21cb5877 100644 --- a/testutils/repository_data/repository/metadata/1.root.json +++ b/testutils/repository_data/repository/metadata/1.root.json @@ -1,4 +1,10 @@ { + "signatures": [ + { + "keyid": "d5fa855fce82db75ec64283e828cc90517df5edf5cdc57e7958a890d6556f5b7", + "sig": "1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee" + } + ], "signed": { "_type": "root", "consistent_snapshot": true, @@ -62,11 +68,5 @@ "spec_version": "1.0.31", "version": 1, "test": "true" - }, - "signatures": [ - { - "keyid": "d5fa855fce82db75ec64283e828cc90517df5edf5cdc57e7958a890d6556f5b7", - "sig": "1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee" - } - ] + } } \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/root.json b/testutils/repository_data/repository/metadata/root.json index d1cba02a..584a3ec9 100644 --- a/testutils/repository_data/repository/metadata/root.json +++ b/testutils/repository_data/repository/metadata/root.json @@ -1,87 +1,71 @@ { + "signatures": [ + { + "keyid": "74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2", + "sig": "d0283ac0653e324ce132e47a518f8a1539b59430efe5cdec58ec53f824bec28628b57dd5fb2452bde83fc8f5d11ab0b7350a9bbcbefc7acc6c447785545fa1e36f1352c9e20dd1ebcc3ab16a2a7ff702e32e481ceba88e0f348dc2cddd26ca577445d00c7194e8656d901fd2382c479555af93a64eef48cf79cdff6ecdcd7cb7" + } + ], "signed": { "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", + "consistent_snapshot": true, + "expires": "2030-08-15T14:30:45.0000001Z", "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], + "142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946": { "keytype": "rsa", "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\\n-----END PUBLIC KEY-----" + "public": "-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHXjYnWGuCIOh5T3XGmgG/RsXWHP\nTbyu7OImP6O+uHg8hui8C1nY/mcJdFdxqgl1vKEco/Nwebh2T8L6XbNfcgV9VVst\nWpeCalZYWi55lZSLe9KixQIAyg15rNdhN9pcD3OuLmFvslgTx+dTbZ3ZoYMbcb4C\n5yqvqzcOoCTQMeWbAgMBAAE=\n-----END PUBLIC KEY-----\n" }, "scheme": "rsassa-pss-sha256" }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", + "282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d": { + "keytype": "rsa", "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + "public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjm6HPktvTGsygQ8Gvmu+zydTN\ne1zqoxLxV7mVRbmsCI4kn7JTHc4fmWZwvo7f/Wbto6Xj5HqGJFSlYIGZuTwZqPg3\nw8wqv8cuPxbmsFSxMoHfzBBIuJe0FlwXFysojbdhrSUqNL84tlwTFXEhePYrpTNM\nDn+9T55B0WJYT/VPxwIDAQAB\n-----END PUBLIC KEY-----\n" }, - "scheme": "ed25519" + "scheme": "rsassa-pss-sha256" }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", + "74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2": { + "keytype": "rsa", "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + "public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDydf/VEpxBOCDoxpM6IVhq9i67\nP9BiVv2zwZSUO/M0RTToAvFvNgDKXwtnp8LyjVk++wMA1aceMa+pS7vYrKvPIJa7\nWIT+mwy86/fIdnllJDMw5tmLr2mE3oBMxOhpEiD2tO+liGacklFNk6nHHorX9S91\niqpdRVa3zJw5ALvLdwIDAQAB\n-----END PUBLIC KEY-----\n" }, - "scheme": "ed25519" + "scheme": "rsassa-pss-sha256" }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", + "8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6": { + "keytype": "rsa", "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + "public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPQoHresXRRRGoinN3bNn+BI23\nKolXdXLGqYkTvr9AjemUQJxbqmvZXHboQMAYw8OuBrRNt5Fz20wjsrJwOBEU5U3n\nHSJI4zYPGckYci0/0Eo2Kjws5BmIj38qgIfhsH4zyZ4FZZ+GLRn+W3i3wl6SfRMC\n/HCg0DDwi75faC0vGQIDAQAB\n-----END PUBLIC KEY-----\n" }, - "scheme": "ed25519" + "scheme": "rsassa-pss-sha256" } }, "roles": { "root": { "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + "74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2" ], "threshold": 1 }, "snapshot": { "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + "8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6" ], "threshold": 1 }, "targets": { "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + "282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d" ], "threshold": 1 }, "timestamp": { "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + "142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946" ], "threshold": 1 } }, - "spec_version": "1.0.0", + "spec_version": "1.0.31", "version": 1 - }, - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ] + } } \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/snapshot.json b/testutils/repository_data/repository/metadata/snapshot.json index 251e99cf..28429701 100644 --- a/testutils/repository_data/repository/metadata/snapshot.json +++ b/testutils/repository_data/repository/metadata/snapshot.json @@ -1,25 +1,19 @@ { - "signed": { - "_type": "snapshot", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "role1.json": { - "version": 1 - }, - "role2.json": { - "version": 1 - }, - "targets.json": { - "version": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - }, - "signatures": [ - { - "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", - "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" - } - ] + "signatures": [ + { + "keyid": "8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6", + "sig": "50d814131d3aace838af726f13a6b4431f78c086b58817f3208d73fe174fe00a4729ad796888bab86ee0cd0cc5746fd8379327e65cd317c4a5f769bf29028bcae1a5bc95a21b15f86a54ba05c3443503037c2c90062825b8a193896814acb67ee000f5816c70f23867686604820efd48ee9d643d1354897c654075076b27ee27" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2030-08-15T14:30:45.0000001Z", + "meta": { + "targets.json": { + "version": 1 + } + }, + "spec_version": "1.0.31", + "version": 1 + } } \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/targets.json b/testutils/repository_data/repository/metadata/targets.json index d18b7b52..f1e50bee 100644 --- a/testutils/repository_data/repository/metadata/targets.json +++ b/testutils/repository_data/repository/metadata/targets.json @@ -1,61 +1,22 @@ { - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role1", - "paths": [ - "file3.txt" - ], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": { - "file1.txt": { - "custom": { - "file_permissions": "0644" - }, - "hashes": { - "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", - "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" - }, - "length": 31 - }, - "file2.txt": { - "hashes": { - "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", - "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" - }, - "length": 39 - } - }, - "version": 1 - }, - "signatures": [ - { - "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", - "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" - } - ] + "signatures": [ + { + "keyid": "282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d", + "sig": "6cffed26499edcb7ee99e885675c3d9c9570d93b78ecba23f71c791dc8cc171db925e2d2105fbb4167e52b947ed08f1441ce536dccd2535957200be63735a2286784d1005d55216b4b1aa6fd0af767d1f003545c1e44ac5208ff592699e8bb36f9c74c8f90cea1893c94f975f78d058f00c97f6fef7b5aed66402cd6e71853d6" + } + ], + "signed": { + "_type": "targets", + "expires": "2030-08-15T14:30:45.0000001Z", + "spec_version": "1.0.31", + "targets": { + "metadata_api_test.go": { + "hashes": { + "sha256": "232ba4f8db1c6e83472f5457a81d9ea03f2db8686dc36161a42e6c809a0a449a" + }, + "length": 19564 + } + }, + "version": 1 + } } \ No newline at end of file diff --git a/testutils/repository_data/repository/metadata/timestamp.json b/testutils/repository_data/repository/metadata/timestamp.json index c1c5a4e1..aa11c742 100644 --- a/testutils/repository_data/repository/metadata/timestamp.json +++ b/testutils/repository_data/repository/metadata/timestamp.json @@ -1,23 +1,19 @@ { - "signed": { - "_type": "timestamp", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "snapshot.json": { - "hashes": { - "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" - }, - "length": 515, - "version": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - }, - "signatures": [ - { - "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", - "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" - } - ] + "signatures": [ + { + "keyid": "142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946", + "sig": "639c9ce3dbb705265b5e9ad6d67fea2b38780c48ff7917e372adace8e50a7a2f054383d5960457a113059be521b8ce7e6d8a5787c600c4850b8c0ed1ae17a931a6bfe794476e7824c6f53df5232561e0a2e146b11dde7889b397c6f8136e2105bbb21b4b59b5addc032a0e755d97e531255f3b458d474184168541e542626e81" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2030-08-15T14:30:45.0000001Z", + "meta": { + "snapshot.json": { + "version": 1 + } + }, + "spec_version": "1.0.31", + "version": 1 + } } \ No newline at end of file From ddb35bdcc908fc71f0351261fbadee0a0044a4ae Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Fri, 30 Jun 2023 10:37:08 +0300 Subject: [PATCH 08/11] Add metadata sign/verify test This change adds test coverage for signing and verigying metadata with a pre-set keys Signed-off-by: Ivana Atanasova --- metadata/metadata.go | 9 +++ metadata/metadata_api_test.go | 96 +++++++++++++++++++++++++++++ testutils/simulators/test_client.go | 2 - 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/metadata/metadata.go b/metadata/metadata.go index 84573142..ee00907c 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -871,3 +871,12 @@ func checkType[T Roles](data []byte) error { // all okay return nil } + +func getSignatureByKeyID(signatures []Signature, keyID string) HexBytes { + for _, sig := range signatures { + if sig.KeyID == keyID { + return sig.Signature + } + } + return []byte{} +} diff --git a/metadata/metadata_api_test.go b/metadata/metadata_api_test.go index c604d27b..ae231973 100644 --- a/metadata/metadata_api_test.go +++ b/metadata/metadata_api_test.go @@ -13,11 +13,14 @@ package metadata import ( "bytes" + "crypto" "encoding/json" "fmt" "testing" simulator "github.com/rdimitrov/go-tuf-metadata/testutils/simulators" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) @@ -272,3 +275,96 @@ func TestToFromBytes(t *testing.T) { assert.Equal(t, string(timestampBytes), string(timestamp2Bytes)) } + +func TestSignVerify(t *testing.T) { + root, err := Root().FromFile(simulator.RepoDir + "/root.json") + assert.NoError(t, err) + + // Locate the public keys we need from root + assert.NotEmpty(t, root.Signed.Roles[TARGETS].KeyIDs) + targetsKeyID := root.Signed.Roles[TARGETS].KeyIDs[0] + assert.NotEmpty(t, root.Signed.Roles[SNAPSHOT].KeyIDs) + snapshotKeyID := root.Signed.Roles[SNAPSHOT].KeyIDs[0] + + // Load sample metadata (targets) and assert ... + targets, err := Targets().FromFile(simulator.RepoDir + "/targets.json") + assert.NoError(t, err) + data, err := targets.Signed.MarshalJSON() + assert.NoError(t, err) + sig := getSignatureByKeyID(targets.Signatures, targetsKeyID) + + // ... it has a single existing signature, + assert.Equal(t, 1, len(targets.Signatures)) + + // ... which is valid for the correct key. + targetsKey := root.Signed.Keys[targetsKeyID] + targetsPublicKey, err := targetsKey.ToPublicKey() + assert.NoError(t, err) + targetsHash := crypto.Hash(0) + if targetsKey.Type != KeyTypeEd25519 { + targetsHash = crypto.SHA256 + } + targetsVerifier, err := signature.LoadVerifier(targetsPublicKey, targetsHash) + assert.NoError(t, err) + err = targetsVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) + assert.NoError(t, err) + + snapshotKey := root.Signed.Keys[snapshotKeyID] + snapshotPublicKey, err := snapshotKey.ToPublicKey() + assert.NoError(t, err) + snapshotHash := crypto.Hash(0) + if snapshotKey.Type != KeyTypeEd25519 { + snapshotHash = crypto.SHA256 + } + snapshotVerifier, err := signature.LoadVerifier(snapshotPublicKey, snapshotHash) + assert.NoError(t, err) + + err = snapshotVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) + assert.ErrorContains(t, err, "crypto/rsa: verification error") + + signer, err := signature.LoadSignerFromPEMFile(simulator.KeystoreDir+"/snapshot_key", crypto.SHA256, cryptoutils.SkipPassword) + // root.Sign(signer) + // root.ToFile(simulator.RepoDir+"/tmp.json", false) + assert.NoError(t, err) + // Append a new signature with the unrelated key and assert that ... + snapshotSig, err := targets.Sign(signer) + assert.NoError(t, err) + // ... there are now two signatures, and + assert.Equal(t, 2, len(targets.Signatures)) + // ... both are valid for the corresponding keys. + err = targetsVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) + assert.NoError(t, err) + err = snapshotVerifier.VerifySignature(bytes.NewReader(snapshotSig.Signature), bytes.NewReader(data)) + assert.NoError(t, err) + // ... the returned (appended) signature is for snapshot key + assert.Equal(t, snapshotSig.KeyID, snapshotKeyID) + + // Create and assign (don't append) a new signature and assert that ... + signer, err = signature.LoadSignerFromPEMFile(simulator.KeystoreDir+"/timestamp_key", crypto.SHA256, cryptoutils.SkipPassword) + assert.NoError(t, err) + + // Append a new signature with the unrelated key and assert that ... + targets.ClearSignatures() + timestampSig, err := targets.Sign(signer) + assert.NoError(t, err) + // ... there now is only one signature, + assert.Equal(t, 1, len(targets.Signatures)) + // ... valid for that key. + assert.NotEmpty(t, root.Signed.Roles[TIMESTAMP].KeyIDs) + timestampKeyID := root.Signed.Roles[TIMESTAMP].KeyIDs[0] + timestampKey := root.Signed.Keys[timestampKeyID] + timestampPublicKey, err := timestampKey.ToPublicKey() + assert.NoError(t, err) + timestampHash := crypto.Hash(0) + if timestampKey.Type != KeyTypeEd25519 { + timestampHash = crypto.SHA256 + } + timestampVerifier, err := signature.LoadVerifier(timestampPublicKey, timestampHash) + assert.NoError(t, err) + + err = timestampVerifier.VerifySignature(bytes.NewReader(timestampSig.Signature), bytes.NewReader(data)) + assert.NoError(t, err) + // TODO: should fail + targetsVerifier.VerifySignature(bytes.NewReader(timestampSig.Signature), bytes.NewReader(data)) + assert.NoError(t, err) +} diff --git a/testutils/simulators/test_client.go b/testutils/simulators/test_client.go index 909e43fd..ddb51578 100644 --- a/testutils/simulators/test_client.go +++ b/testutils/simulators/test_client.go @@ -59,8 +59,6 @@ func SetupTestDirs() error { return err } - // TODO: load keys to keystore map - return nil } From 76f939ea98747c3b113b7ec366613a6d27118a34 Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Fri, 30 Jun 2023 13:41:21 +0300 Subject: [PATCH 09/11] Cleanup unnecessary functionality This change removes unused keys and test utils for the metadata unit tests. The removed test utils include filesystem simulator, which is replaced by the setup functionality and some tidy-up around the changes Signed-off-by: Ivana Atanasova --- metadata/metadata_api_test.go | 53 +++++------ testutils/repository_data/keystore/root_key2 | 1 - .../repository_data/keystore/root_key2.pub | 1 - testutils/repository_data/keystore/root_key3 | 1 - .../repository_data/keystore/root_key3.pub | 1 - testutils/simulators/file_system.go | 94 ------------------- .../test_client.go => testutils/setup.go} | 39 ++++++-- 7 files changed, 58 insertions(+), 132 deletions(-) delete mode 100644 testutils/repository_data/keystore/root_key2 delete mode 100644 testutils/repository_data/keystore/root_key2.pub delete mode 100644 testutils/repository_data/keystore/root_key3 delete mode 100644 testutils/repository_data/keystore/root_key3.pub delete mode 100644 testutils/simulators/file_system.go rename testutils/{simulators/test_client.go => testutils/setup.go} (64%) diff --git a/metadata/metadata_api_test.go b/metadata/metadata_api_test.go index ae231973..d7be2182 100644 --- a/metadata/metadata_api_test.go +++ b/metadata/metadata_api_test.go @@ -16,9 +16,10 @@ import ( "crypto" "encoding/json" "fmt" + "os" "testing" - simulator "github.com/rdimitrov/go-tuf-metadata/testutils/simulators" + testutils "github.com/rdimitrov/go-tuf-metadata/testutils/testutils" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" log "github.com/sirupsen/logrus" @@ -27,8 +28,8 @@ import ( func TestMain(m *testing.M) { - err := simulator.SetupTestDirs() - defer simulator.Cleanup() + err := testutils.SetupTestDirs() + defer testutils.Cleanup() if err != nil { log.Fatalf("failed to setup test dirs: %v", err) @@ -48,8 +49,8 @@ func TestGenericRead(t *testing.T) { _, err = Timestamp().FromBytes([]byte(badMetadata)) assert.ErrorContains(t, err, "expected metadata type timestamp, got - bad-metadata") - badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", simulator.RepoDir) - err = simulator.CreateFile(badMetadataPath, []byte(badMetadata)) + badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", testutils.RepoDir) + err = os.WriteFile(badMetadataPath, []byte(badMetadata), 0644) assert.NoError(t, err) assert.FileExists(t, badMetadataPath) @@ -62,26 +63,26 @@ func TestGenericRead(t *testing.T) { _, err = Timestamp().FromFile(badMetadataPath) assert.ErrorContains(t, err, "expected metadata type timestamp, got - bad-metadata") - err = simulator.DeleteFile(badMetadataPath) + err = os.RemoveAll(badMetadataPath) assert.NoError(t, err) assert.NoFileExists(t, badMetadataPath) } func TestMDReadWriteFileExceptions(t *testing.T) { // Test writing to a file with bad filename - badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", simulator.RepoDir) + badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", testutils.RepoDir) _, err := Root().FromFile(badMetadataPath) assert.ErrorContains(t, err, fmt.Sprintf("open %s: no such file or directory", badMetadataPath)) // Test serializing to a file with bad filename - root, err := Root().FromFile(fmt.Sprintf("%s/root.json", simulator.RepoDir)) + root, err := Root().FromFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) assert.NoError(t, err) err = root.ToFile("", false) assert.ErrorContains(t, err, "no such file or directory") } func TestRootReadWriteReadCompare(t *testing.T) { - path1 := simulator.RepoDir + "/root.json" + path1 := testutils.RepoDir + "/root.json" root1, err := Root().FromFile(path1) assert.NoError(t, err) @@ -98,12 +99,12 @@ func TestRootReadWriteReadCompare(t *testing.T) { assert.NoError(t, err) assert.Equal(t, bytes1, bytes2) - err = simulator.DeleteFile(path2) + err = os.RemoveAll(path2) assert.NoError(t, err) } func TestSnapshotReadWriteReadCompare(t *testing.T) { - path1 := simulator.RepoDir + "/snapshot.json" + path1 := testutils.RepoDir + "/snapshot.json" snaphot1, err := Snapshot().FromFile(path1) assert.NoError(t, err) @@ -120,12 +121,12 @@ func TestSnapshotReadWriteReadCompare(t *testing.T) { assert.NoError(t, err) assert.Equal(t, bytes1, bytes2) - err = simulator.DeleteFile(path2) + err = os.RemoveAll(path2) assert.NoError(t, err) } func TestTargetsReadWriteReadCompare(t *testing.T) { - path1 := simulator.RepoDir + "/targets.json" + path1 := testutils.RepoDir + "/targets.json" targets1, err := Targets().FromFile(path1) assert.NoError(t, err) @@ -142,12 +143,12 @@ func TestTargetsReadWriteReadCompare(t *testing.T) { assert.NoError(t, err) assert.Equal(t, bytes1, bytes2) - err = simulator.DeleteFile(path2) + err = os.RemoveAll(path2) assert.NoError(t, err) } func TestTimestampReadWriteReadCompare(t *testing.T) { - path1 := simulator.RepoDir + "/timestamp.json" + path1 := testutils.RepoDir + "/timestamp.json" timestamp1, err := Timestamp().FromFile(path1) assert.NoError(t, err) @@ -164,13 +165,13 @@ func TestTimestampReadWriteReadCompare(t *testing.T) { assert.NoError(t, err) assert.Equal(t, bytes1, bytes2) - err = simulator.DeleteFile(path2) + err = os.RemoveAll(path2) assert.NoError(t, err) } func TestSerializeAndValidate(t *testing.T) { // Assert that by changing one required attribute validation will fail. - root, err := Root().FromFile(simulator.RepoDir + "/root.json") + root, err := Root().FromFile(testutils.RepoDir + "/root.json") assert.NoError(t, err) root.Signed.Version = 0 @@ -192,7 +193,7 @@ func TrimBytes(data []byte) ([]byte, error) { func TestToFromBytes(t *testing.T) { // ROOT - data, err := simulator.ReadFile(simulator.RepoDir + "/root.json") + data, err := os.ReadFile(testutils.RepoDir + "/root.json") assert.NoError(t, err) data, err = TrimBytes(data) assert.NoError(t, err) @@ -215,7 +216,7 @@ func TestToFromBytes(t *testing.T) { assert.Equal(t, rootBytes, root2Bytes) // SNAPSHOT - data, err = simulator.ReadFile(simulator.RepoDir + "/snapshot.json") + data, err = os.ReadFile(testutils.RepoDir + "/snapshot.json") assert.NoError(t, err) data, err = TrimBytes(data) assert.NoError(t, err) @@ -235,7 +236,7 @@ func TestToFromBytes(t *testing.T) { assert.Equal(t, string(snapshotBytes), string(snapshot2Bytes)) // TARGETS - data, err = simulator.ReadFile(simulator.RepoDir + "/targets.json") + data, err = os.ReadFile(testutils.RepoDir + "/targets.json") assert.NoError(t, err) data, err = TrimBytes(data) assert.NoError(t, err) @@ -255,7 +256,7 @@ func TestToFromBytes(t *testing.T) { assert.Equal(t, string(targetsBytes), string(targets2Bytes)) // TIMESTAMP - data, err = simulator.ReadFile(simulator.RepoDir + "/timestamp.json") + data, err = os.ReadFile(testutils.RepoDir + "/timestamp.json") assert.NoError(t, err) data, err = TrimBytes(data) assert.NoError(t, err) @@ -277,7 +278,7 @@ func TestToFromBytes(t *testing.T) { } func TestSignVerify(t *testing.T) { - root, err := Root().FromFile(simulator.RepoDir + "/root.json") + root, err := Root().FromFile(testutils.RepoDir + "/root.json") assert.NoError(t, err) // Locate the public keys we need from root @@ -287,7 +288,7 @@ func TestSignVerify(t *testing.T) { snapshotKeyID := root.Signed.Roles[SNAPSHOT].KeyIDs[0] // Load sample metadata (targets) and assert ... - targets, err := Targets().FromFile(simulator.RepoDir + "/targets.json") + targets, err := Targets().FromFile(testutils.RepoDir + "/targets.json") assert.NoError(t, err) data, err := targets.Signed.MarshalJSON() assert.NoError(t, err) @@ -322,9 +323,7 @@ func TestSignVerify(t *testing.T) { err = snapshotVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.ErrorContains(t, err, "crypto/rsa: verification error") - signer, err := signature.LoadSignerFromPEMFile(simulator.KeystoreDir+"/snapshot_key", crypto.SHA256, cryptoutils.SkipPassword) - // root.Sign(signer) - // root.ToFile(simulator.RepoDir+"/tmp.json", false) + signer, err := signature.LoadSignerFromPEMFile(testutils.KeystoreDir+"/snapshot_key", crypto.SHA256, cryptoutils.SkipPassword) assert.NoError(t, err) // Append a new signature with the unrelated key and assert that ... snapshotSig, err := targets.Sign(signer) @@ -340,7 +339,7 @@ func TestSignVerify(t *testing.T) { assert.Equal(t, snapshotSig.KeyID, snapshotKeyID) // Create and assign (don't append) a new signature and assert that ... - signer, err = signature.LoadSignerFromPEMFile(simulator.KeystoreDir+"/timestamp_key", crypto.SHA256, cryptoutils.SkipPassword) + signer, err = signature.LoadSignerFromPEMFile(testutils.KeystoreDir+"/timestamp_key", crypto.SHA256, cryptoutils.SkipPassword) assert.NoError(t, err) // Append a new signature with the unrelated key and assert that ... diff --git a/testutils/repository_data/keystore/root_key2 b/testutils/repository_data/keystore/root_key2 deleted file mode 100644 index 82229465..00000000 --- a/testutils/repository_data/keystore/root_key2 +++ /dev/null @@ -1 +0,0 @@ -77c02ab5647ee765d5f6c5fc202a5b32@@@@100000@@@@7c73c1100fab52dc8695c1b955d31770ed6e53f1820d9020aeb6541c948573d9@@@@98280307ffa9c5f6ff1fea1a4b79d0ea@@@@f3342882b1cf842e3377ab4205c0ca8fab564cc55fa742f55b364a1ac597e93d8c56a9a6e6bbb6a812556077be44a1066ac6781a6ed34b86beaf3985f846f007dab31c46af562e921f03c1ea8d299f15324ab137aa426ee61d396a7e20191aa71a70b670775b2ad48f25de367fb48881c55e93f468c6e59402907e82985c27c94c715161c85c5c1904353ba33c3d129988029f03a2d7d00720118697baaf73a3c4e72f8e538b4323866fe525ddccfcfc6dd45598545f65cd7ab581f5172bc253416283a66621eb03dbabaf33923bb1963f9f8cbae6fd6a1c86736a8f80c8d1ba3cbc3f53b0123ba9b0bdd44f25b65033b19a50ee978d2687d6a2ee724515a20026d0213ced59cda9bfdf37c82c59e1356795fd603d85996f448a3c9357b32de2042997a1d27353ee3866c0ed5218d633e0b28991119d77d147354c7fa2de8a168d17efdfd5fa9a8e528bd47ede4ff697 \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key2.pub b/testutils/repository_data/keystore/root_key2.pub deleted file mode 100644 index dd5c43b5..00000000 --- a/testutils/repository_data/keystore/root_key2.pub +++ /dev/null @@ -1 +0,0 @@ -{"keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": ["sha256", "sha512"], "keyval": {"public": "3ba219e69666298bce5d1d653a166346aef807c02e32a846aaefcb5190fddeb4"}} \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key3 b/testutils/repository_data/keystore/root_key3 deleted file mode 100644 index 89c0b2cc..00000000 --- a/testutils/repository_data/keystore/root_key3 +++ /dev/null @@ -1 +0,0 @@ -a3d266f446cb23c0248feed240a8a85a@@@@100000@@@@61ea41c73d4b1d8bd7566a9884a2fdb88c1d4e48550341e532768f98c8f4bd3c@@@@46b15764c50c934fcfc041a5fa207337@@@@d84b8c473d5f42d2bbceca28b0087c2c5908673b2a92eb8f1ca91dacc27c1cfac24c98d06191f6f54633dd428e9ca0987f183e8f34322a104dc38a0f4fefcc168f21e203e3abc5842f132df2dcb61d6b31dc19d0ecb50e898655f81e9b8a9730f2bff4c5ca4b6fc0b572a7e3672b6dc814ed127c964d960a57155c29eccf44824442d3c6761662ed2d8a1c48a3222d0f0cb1a58f543ccd852c247522595d987d95d1bf49dfdffaf33f18085460dac791d81347cc576a83c6ebca2625d26ddd294e74fa67f676a02d533b52fc9702237b2c898469a30753d98b091cd6aa713aa7b0c4c741684674084b27862e64adf4b1e88fa22cfcf6eeae8608dd818a4cba020058fa7271028ea9d9a7302c9e50e82972a82ac2080201c0fb9f2fb1cadfe97d62470414428227add1c40594f5135a8169d0d7d0889cb4a1949b015e65f5dc656204c58c463acc5b7872f4a078d0bc5a09a7795187e360e7b225892601aa9065086b24397f653d20e59a656ec86ef94e64d5baf16080f12a7f2461b92f99dfb5bf2e4dadec91cc72d8eede952449fd586c863734d84f31e036ecc96c55ab7baa9b049c20b8281a7c28f5ca42d9cfad6498f51ee907bfd9dc17e2a1bc9b69145ee82a86a90817394c01770581727889d3ba1791592c7ac2e74753485f1811cc4477078732873185240fc1572927d2fef210066bdf015471bd9d1683e8074b3fb6957246589dc62dea4843a17a7c734ae45ae20d31f0083a32d3310fae459fe3fbf7c763e5e4ead4acd9b0233e45237f4465576e85ff707fe316488f329d5bc73596b104cc28b926d6b1f5a3d26a0a6ec534a3cbc54cab97f5cea51f17b8d7f1cc6c9977275c34ee4942dd3e22a19ae1e4252199226cc4fd60 \ No newline at end of file diff --git a/testutils/repository_data/keystore/root_key3.pub b/testutils/repository_data/keystore/root_key3.pub deleted file mode 100644 index ee5d4872..00000000 --- a/testutils/repository_data/keystore/root_key3.pub +++ /dev/null @@ -1 +0,0 @@ -{"keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": ["sha256", "sha512"], "keyval": {"public": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4huWFUZelzzZk2xLwnLqyc2q7cfI\nIqgg3qOWSddQ3Q/GBXCzgg7zqNqS+xSt+D3gy3mMBbkeo+6OVm8/W9BrqQ=="}} \ No newline at end of file diff --git a/testutils/simulators/file_system.go b/testutils/simulators/file_system.go deleted file mode 100644 index bdcb83a1..00000000 --- a/testutils/simulators/file_system.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2023 VMware, Inc. -// -// This product is licensed to you under the BSD-2 license (the "License"). -// You may not use this product except in compliance with the BSD-2 License. -// This product may include a number of subcomponents with separate copyright -// notices and license terms. Your use of these subcomponents is subject to -// the terms and conditions of the subcomponent's license, as noted in the -// LICENSE file. -// -// SPDX-License-Identifier: BSD-2-Clause - -package simulator - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" -) - -// osFS implements fileSystem using the local disk. -type osFS struct{} - -func (*osFS) MkdirTemp(dir string, pattern string) (string, error) { - return os.MkdirTemp(dir, pattern) -} - -func (*osFS) TempDir() string { - return os.TempDir() -} - -func (*osFS) Mkdir(name string) error { - return os.Mkdir(name, 0750) -} - -func (*osFS) Copy(fromPath string, toPath string) error { - err := os.MkdirAll(toPath, 0750) - if err != nil { - log.Debugf("failed to create directory %s: %v", toPath, err) - } - files, err := os.ReadDir(fromPath) - if err != nil { - log.Debugf("failed to read path %s: %v", fromPath, err) - return err - } - for _, file := range files { - data, err := os.ReadFile(fmt.Sprintf("%s/%s", fromPath, file.Name())) - if err != nil { - log.Debugf("failed to read file %s: %v", file.Name(), err) - } - filePath := fmt.Sprintf("%s/%s", toPath, file.Name()) - err = os.WriteFile(filePath, data, 0750) - if err != nil { - log.Debugf("failed to write file %s: %v", filePath, err) - } - } - return nil -} - -func (*osFS) ReadFile(name string) ([]byte, error) { - return os.ReadFile(name) -} - -func (*osFS) WriteFile(name string, data []byte) error { - return os.WriteFile(name, data, 0644) -} - -func (*osFS) RemoveAll(path string) error { - return os.RemoveAll(path) -} - -var fs fileSystem = &osFS{} - -type fileSystem interface { - TempDir() string - Mkdir(name string) error - MkdirTemp(dir string, pattern string) (string, error) - Copy(fromPath string, toPath string) error - ReadFile(name string) ([]byte, error) - WriteFile(name string, data []byte) error - RemoveAll(path string) error -} - -func CreateFile(path string, data []byte) error { - return fs.WriteFile(path, data) -} - -func DeleteFile(path string) error { - return fs.RemoveAll(path) -} - -func ReadFile(name string) ([]byte, error) { - return fs.ReadFile(name) -} diff --git a/testutils/simulators/test_client.go b/testutils/testutils/setup.go similarity index 64% rename from testutils/simulators/test_client.go rename to testutils/testutils/setup.go index ddb51578..ea51d499 100644 --- a/testutils/simulators/test_client.go +++ b/testutils/testutils/setup.go @@ -9,10 +9,11 @@ // // SPDX-License-Identifier: BSD-2-Clause -package simulator +package testutils import ( "fmt" + "os" "path/filepath" log "github.com/sirupsen/logrus" @@ -25,9 +26,9 @@ var ( ) func SetupTestDirs() error { - tmp := fs.TempDir() + tmp := os.TempDir() var err error - TempDir, err = fs.MkdirTemp(tmp, "0750") + TempDir, err = os.MkdirTemp(tmp, "0750") if err != nil { log.Fatal("failed to create temporary directory: ", err) return err @@ -38,14 +39,14 @@ func SetupTestDirs() error { if err != nil { log.Debugf("failed to get absolute path: %v", err) } - err = fs.Copy(absPath, RepoDir) + err = Copy(absPath, RepoDir) if err != nil { log.Debugf("failed to copy metadata to %s: %v", RepoDir, err) return err } KeystoreDir = fmt.Sprintf("%s/keystore", TempDir) - err = fs.Mkdir(KeystoreDir) + err = os.Mkdir(KeystoreDir, 0750) if err != nil { log.Debugf("failed to create keystore dir %s: %v", KeystoreDir, err) } @@ -53,7 +54,7 @@ func SetupTestDirs() error { if err != nil { log.Debugf("failed to get absolute path: %v", err) } - err = fs.Copy(absPath, KeystoreDir) + err = Copy(absPath, KeystoreDir) if err != nil { log.Debugf("failed to copy keystore to %s: %v", KeystoreDir, err) return err @@ -62,9 +63,33 @@ func SetupTestDirs() error { return nil } +func Copy(fromPath string, toPath string) error { + err := os.MkdirAll(toPath, 0750) + if err != nil { + log.Debugf("failed to create directory %s: %v", toPath, err) + } + files, err := os.ReadDir(fromPath) + if err != nil { + log.Debugf("failed to read path %s: %v", fromPath, err) + return err + } + for _, file := range files { + data, err := os.ReadFile(fmt.Sprintf("%s/%s", fromPath, file.Name())) + if err != nil { + log.Debugf("failed to read file %s: %v", file.Name(), err) + } + filePath := fmt.Sprintf("%s/%s", toPath, file.Name()) + err = os.WriteFile(filePath, data, 0750) + if err != nil { + log.Debugf("failed to write file %s: %v", filePath, err) + } + } + return nil +} + func Cleanup() { log.Printf("cleaning temporary directory: %s\n", TempDir) - err := fs.RemoveAll(TempDir) + err := os.RemoveAll(TempDir) if err != nil { log.Fatalf("failed to cleanup test directories: %v", err) } From 79357c224096502d39a9695f4178b37338acebe0 Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Fri, 30 Jun 2023 15:25:58 +0300 Subject: [PATCH 10/11] Fix metadata api tests to verify error type This change updates error assertions in the metadata api tests to compare error types rather than only a message Signed-off-by: Ivana Atanasova --- metadata/metadata_api_test.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/metadata/metadata_api_test.go b/metadata/metadata_api_test.go index d7be2182..45cb88c9 100644 --- a/metadata/metadata_api_test.go +++ b/metadata/metadata_api_test.go @@ -16,6 +16,7 @@ import ( "crypto" "encoding/json" "fmt" + "io/fs" "os" "testing" @@ -24,6 +25,7 @@ import ( "github.com/sigstore/sigstore/pkg/signature" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "golang.org/x/sys/unix" ) func TestMain(m *testing.M) { @@ -41,13 +43,13 @@ func TestGenericRead(t *testing.T) { // Assert that it chokes correctly on an unknown metadata type badMetadata := "{\"signed\": {\"_type\": \"bad-metadata\"}}" _, err := Root().FromBytes([]byte(badMetadata)) - assert.ErrorContains(t, err, "expected metadata type root, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - bad-metadata"}) _, err = Snapshot().FromBytes([]byte(badMetadata)) - assert.ErrorContains(t, err, "expected metadata type snapshot, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - bad-metadata"}) _, err = Targets().FromBytes([]byte(badMetadata)) - assert.ErrorContains(t, err, "expected metadata type targets, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - bad-metadata"}) _, err = Timestamp().FromBytes([]byte(badMetadata)) - assert.ErrorContains(t, err, "expected metadata type timestamp, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - bad-metadata"}) badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", testutils.RepoDir) err = os.WriteFile(badMetadataPath, []byte(badMetadata), 0644) @@ -55,13 +57,13 @@ func TestGenericRead(t *testing.T) { assert.FileExists(t, badMetadataPath) _, err = Root().FromFile(badMetadataPath) - assert.ErrorContains(t, err, "expected metadata type root, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - bad-metadata"}) _, err = Snapshot().FromFile(badMetadataPath) - assert.ErrorContains(t, err, "expected metadata type snapshot, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - bad-metadata"}) _, err = Targets().FromFile(badMetadataPath) - assert.ErrorContains(t, err, "expected metadata type targets, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - bad-metadata"}) _, err = Timestamp().FromFile(badMetadataPath) - assert.ErrorContains(t, err, "expected metadata type timestamp, got - bad-metadata") + assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - bad-metadata"}) err = os.RemoveAll(badMetadataPath) assert.NoError(t, err) @@ -72,13 +74,23 @@ func TestMDReadWriteFileExceptions(t *testing.T) { // Test writing to a file with bad filename badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", testutils.RepoDir) _, err := Root().FromFile(badMetadataPath) - assert.ErrorContains(t, err, fmt.Sprintf("open %s: no such file or directory", badMetadataPath)) + expectedErr := fs.PathError{ + Op: "open", + Path: badMetadataPath, + Err: unix.ENOENT, + } + assert.ErrorIs(t, err, expectedErr.Err) // Test serializing to a file with bad filename root, err := Root().FromFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) assert.NoError(t, err) err = root.ToFile("", false) - assert.ErrorContains(t, err, "no such file or directory") + expectedErr = fs.PathError{ + Op: "open", + Path: "", + Err: unix.ENOENT, + } + assert.ErrorIs(t, err, expectedErr.Err) } func TestRootReadWriteReadCompare(t *testing.T) { From cc2bfeebf2488adffb410bcea45db57fb38a2687 Mon Sep 17 00:00:00 2001 From: Ivana Atanasova Date: Fri, 21 Jul 2023 21:38:14 +0300 Subject: [PATCH 11/11] Improve metadata tests This change provides improvements to the metadata api tests Signed-off-by: Ivana Atanasova --- metadata/metadata.go | 9 -- metadata/metadata_api_test.go | 195 +++++++++++++++++++--------------- metadata/metadata_test.go | 49 +++------ 3 files changed, 126 insertions(+), 127 deletions(-) diff --git a/metadata/metadata.go b/metadata/metadata.go index ee00907c..84573142 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -871,12 +871,3 @@ func checkType[T Roles](data []byte) error { // all okay return nil } - -func getSignatureByKeyID(signatures []Signature, keyID string) HexBytes { - for _, sig := range signatures { - if sig.KeyID == keyID { - return sig.Signature - } - } - return []byte{} -} diff --git a/metadata/metadata_api_test.go b/metadata/metadata_api_test.go index 45cb88c9..15544926 100644 --- a/metadata/metadata_api_test.go +++ b/metadata/metadata_api_test.go @@ -14,7 +14,6 @@ package metadata import ( "bytes" "crypto" - "encoding/json" "fmt" "io/fs" "os" @@ -70,6 +69,40 @@ func TestGenericRead(t *testing.T) { assert.NoFileExists(t, badMetadataPath) } +func TestGenericReadFromMismatchingRoles(t *testing.T) { + // Test failing to load other roles from root metadata + _, err := Snapshot().FromFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - root"}) + _, err = Timestamp().FromFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - root"}) + _, err = Targets().FromFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - root"}) + + // Test failing to load other roles from targets metadata + _, err = Snapshot().FromFile(fmt.Sprintf("%s/targets.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - targets"}) + _, err = Timestamp().FromFile(fmt.Sprintf("%s/targets.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - targets"}) + _, err = Root().FromFile(fmt.Sprintf("%s/targets.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - targets"}) + + // Test failing to load other roles from timestamp metadata + _, err = Snapshot().FromFile(fmt.Sprintf("%s/timestamp.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - timestamp"}) + _, err = Targets().FromFile(fmt.Sprintf("%s/timestamp.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - timestamp"}) + _, err = Root().FromFile(fmt.Sprintf("%s/timestamp.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - timestamp"}) + + // Test failing to load other roles from snapshot metadata + _, err = Targets().FromFile(fmt.Sprintf("%s/snapshot.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - snapshot"}) + _, err = Timestamp().FromFile(fmt.Sprintf("%s/snapshot.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - snapshot"}) + _, err = Root().FromFile(fmt.Sprintf("%s/snapshot.json", testutils.RepoDir)) + assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - snapshot"}) +} + func TestMDReadWriteFileExceptions(t *testing.T) { // Test writing to a file with bad filename badMetadataPath := fmt.Sprintf("%s/bad-metadata.json", testutils.RepoDir) @@ -82,8 +115,7 @@ func TestMDReadWriteFileExceptions(t *testing.T) { assert.ErrorIs(t, err, expectedErr.Err) // Test serializing to a file with bad filename - root, err := Root().FromFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) - assert.NoError(t, err) + root := Root(fixedExpire) err = root.ToFile("", false) expectedErr = fs.PathError{ Op: "open", @@ -93,25 +125,59 @@ func TestMDReadWriteFileExceptions(t *testing.T) { assert.ErrorIs(t, err, expectedErr.Err) } +func TestCompareFromBytesFromFileToBytes(t *testing.T) { + rootBytesWant, err := os.ReadFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) + assert.NoError(t, err) + root, err := Root().FromFile(fmt.Sprintf("%s/root.json", testutils.RepoDir)) + assert.NoError(t, err) + rootBytesActual, err := root.ToBytes(true) + assert.NoError(t, err) + assert.Equal(t, rootBytesWant, rootBytesActual) + + targetsBytesWant, err := os.ReadFile(fmt.Sprintf("%s/targets.json", testutils.RepoDir)) + assert.NoError(t, err) + targets, err := Targets().FromFile(fmt.Sprintf("%s/targets.json", testutils.RepoDir)) + assert.NoError(t, err) + targetsBytesActual, err := targets.ToBytes(true) + assert.NoError(t, err) + assert.Equal(t, targetsBytesWant, targetsBytesActual) + + snapshotBytesWant, err := os.ReadFile(fmt.Sprintf("%s/snapshot.json", testutils.RepoDir)) + assert.NoError(t, err) + snapshot, err := Snapshot().FromFile(fmt.Sprintf("%s/snapshot.json", testutils.RepoDir)) + assert.NoError(t, err) + snapshotBytesActual, err := snapshot.ToBytes(true) + assert.NoError(t, err) + assert.Equal(t, snapshotBytesWant, snapshotBytesActual) + + timestampBytesWant, err := os.ReadFile(fmt.Sprintf("%s/timestamp.json", testutils.RepoDir)) + assert.NoError(t, err) + timestamp, err := Timestamp().FromFile(fmt.Sprintf("%s/timestamp.json", testutils.RepoDir)) + assert.NoError(t, err) + timestampBytesActual, err := timestamp.ToBytes(true) + assert.NoError(t, err) + assert.Equal(t, timestampBytesWant, timestampBytesActual) +} + func TestRootReadWriteReadCompare(t *testing.T) { - path1 := testutils.RepoDir + "/root.json" - root1, err := Root().FromFile(path1) + src := testutils.RepoDir + "/root.json" + srcRoot, err := Root().FromFile(src) assert.NoError(t, err) - path2 := path1 + ".tmp" - err = root1.ToFile(path2, false) + dst := src + ".tmp" + err = srcRoot.ToFile(dst, false) assert.NoError(t, err) - root2, err := Root().FromFile(path2) + dstRoot, err := Root().FromFile(dst) assert.NoError(t, err) - bytes1, err := root1.ToBytes(false) + srcBytes, err := srcRoot.ToBytes(false) assert.NoError(t, err) - bytes2, err := root2.ToBytes(false) + dstBytes, err := dstRoot.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, bytes1, bytes2) + assert.Equal(t, srcBytes, dstBytes) - err = os.RemoveAll(path2) + err = os.RemoveAll(dst) assert.NoError(t, err) } @@ -181,34 +247,10 @@ func TestTimestampReadWriteReadCompare(t *testing.T) { assert.NoError(t, err) } -func TestSerializeAndValidate(t *testing.T) { - // Assert that by changing one required attribute validation will fail. - root, err := Root().FromFile(testutils.RepoDir + "/root.json") - assert.NoError(t, err) - root.Signed.Version = 0 - - _, err = root.ToBytes(false) - // TODO: refering to python-tuf, this should fail - assert.NoError(t, err) -} - -func TrimBytes(data []byte) ([]byte, error) { - buffer := new(bytes.Buffer) - err := json.Compact(buffer, data) - if err != nil { - log.Debugf("failed to trim bytes: %v", err) - return data, err - } - data = buffer.Bytes() - return data, nil -} - func TestToFromBytes(t *testing.T) { // ROOT data, err := os.ReadFile(testutils.RepoDir + "/root.json") assert.NoError(t, err) - data, err = TrimBytes(data) - assert.NoError(t, err) root, err := Root().FromBytes(data) assert.NoError(t, err) @@ -216,76 +258,70 @@ func TestToFromBytes(t *testing.T) { // for two cases for the serializer: noncompact and compact. // Case 1: test noncompact by overriding the default serializer. - rootBytes, err := root.ToBytes(false) + rootBytesWant, err := root.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, data, rootBytes) + assert.Equal(t, data, rootBytesWant) // Case 2: test compact by using the default serializer. - root2, err := Root().FromBytes(rootBytes) + root2, err := Root().FromBytes(rootBytesWant) assert.NoError(t, err) - root2Bytes, err := root2.ToBytes(false) + rootBytesActual, err := root2.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, rootBytes, root2Bytes) + assert.Equal(t, rootBytesWant, rootBytesActual) // SNAPSHOT data, err = os.ReadFile(testutils.RepoDir + "/snapshot.json") assert.NoError(t, err) - data, err = TrimBytes(data) - assert.NoError(t, err) snapshot, err := Snapshot().FromBytes(data) assert.NoError(t, err) // Case 1: test noncompact by overriding the default serializer. - snapshotBytes, err := snapshot.ToBytes(false) + snapshotBytesWant, err := snapshot.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, string(data), string(snapshotBytes)) + assert.Equal(t, string(data), string(snapshotBytesWant)) // Case 2: test compact by using the default serializer. - snapshot2, err := Snapshot().FromBytes(snapshotBytes) + snapshot2, err := Snapshot().FromBytes(snapshotBytesWant) assert.NoError(t, err) - snapshot2Bytes, err := snapshot2.ToBytes(false) + snapshotBytesActual, err := snapshot2.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, string(snapshotBytes), string(snapshot2Bytes)) + assert.Equal(t, string(snapshotBytesWant), string(snapshotBytesActual)) // TARGETS data, err = os.ReadFile(testutils.RepoDir + "/targets.json") assert.NoError(t, err) - data, err = TrimBytes(data) - assert.NoError(t, err) targets, err := Targets().FromBytes(data) assert.NoError(t, err) // Case 1: test noncompact by overriding the default serializer. - targetsBytes, err := targets.ToBytes(false) + targetsBytesWant, err := targets.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, string(data), string(targetsBytes)) + assert.Equal(t, string(data), string(targetsBytesWant)) // Case 2: test compact by using the default serializer. - targets2, err := Targets().FromBytes(targetsBytes) + targets2, err := Targets().FromBytes(targetsBytesWant) assert.NoError(t, err) - targets2Bytes, err := targets2.ToBytes(false) + targetsBytesActual, err := targets2.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, string(targetsBytes), string(targets2Bytes)) + assert.Equal(t, string(targetsBytesWant), string(targetsBytesActual)) // TIMESTAMP data, err = os.ReadFile(testutils.RepoDir + "/timestamp.json") assert.NoError(t, err) - data, err = TrimBytes(data) - assert.NoError(t, err) timestamp, err := Timestamp().FromBytes(data) assert.NoError(t, err) // Case 1: test noncompact by overriding the default serializer. - timestampBytes, err := timestamp.ToBytes(false) + timestampBytesWant, err := timestamp.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, string(data), string(timestampBytes)) + assert.Equal(t, string(data), string(timestampBytesWant)) // Case 2: test compact by using the default serializer. - timestamp2, err := Timestamp().FromBytes(timestampBytes) + timestamp2, err := Timestamp().FromBytes(timestampBytesWant) assert.NoError(t, err) - timestamp2Bytes, err := timestamp2.ToBytes(false) + timestampBytesActual, err := timestamp2.ToBytes(true) assert.NoError(t, err) - assert.Equal(t, string(timestampBytes), string(timestamp2Bytes)) + assert.Equal(t, string(timestampBytesWant), string(timestampBytesActual)) } @@ -298,13 +334,15 @@ func TestSignVerify(t *testing.T) { targetsKeyID := root.Signed.Roles[TARGETS].KeyIDs[0] assert.NotEmpty(t, root.Signed.Roles[SNAPSHOT].KeyIDs) snapshotKeyID := root.Signed.Roles[SNAPSHOT].KeyIDs[0] + assert.NotEmpty(t, root.Signed.Roles[TIMESTAMP].KeyIDs) + timestampKeyID := root.Signed.Roles[TIMESTAMP].KeyIDs[0] // Load sample metadata (targets) and assert ... targets, err := Targets().FromFile(testutils.RepoDir + "/targets.json") assert.NoError(t, err) + sig := getSignatureByKeyID(targets.Signatures, targetsKeyID) data, err := targets.Signed.MarshalJSON() assert.NoError(t, err) - sig := getSignatureByKeyID(targets.Signatures, targetsKeyID) // ... it has a single existing signature, assert.Equal(t, 1, len(targets.Signatures)) @@ -313,31 +351,25 @@ func TestSignVerify(t *testing.T) { targetsKey := root.Signed.Keys[targetsKeyID] targetsPublicKey, err := targetsKey.ToPublicKey() assert.NoError(t, err) - targetsHash := crypto.Hash(0) - if targetsKey.Type != KeyTypeEd25519 { - targetsHash = crypto.SHA256 - } + targetsHash := crypto.SHA256 targetsVerifier, err := signature.LoadVerifier(targetsPublicKey, targetsHash) assert.NoError(t, err) err = targetsVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.NoError(t, err) + // ... and invalid for an unrelated key snapshotKey := root.Signed.Keys[snapshotKeyID] snapshotPublicKey, err := snapshotKey.ToPublicKey() assert.NoError(t, err) - snapshotHash := crypto.Hash(0) - if snapshotKey.Type != KeyTypeEd25519 { - snapshotHash = crypto.SHA256 - } + snapshotHash := crypto.SHA256 snapshotVerifier, err := signature.LoadVerifier(snapshotPublicKey, snapshotHash) assert.NoError(t, err) - err = snapshotVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.ErrorContains(t, err, "crypto/rsa: verification error") + // Append a new signature with the unrelated key and assert that ... signer, err := signature.LoadSignerFromPEMFile(testutils.KeystoreDir+"/snapshot_key", crypto.SHA256, cryptoutils.SkipPassword) assert.NoError(t, err) - // Append a new signature with the unrelated key and assert that ... snapshotSig, err := targets.Sign(signer) assert.NoError(t, err) // ... there are now two signatures, and @@ -350,32 +382,25 @@ func TestSignVerify(t *testing.T) { // ... the returned (appended) signature is for snapshot key assert.Equal(t, snapshotSig.KeyID, snapshotKeyID) - // Create and assign (don't append) a new signature and assert that ... + // Clear all signatures and add a new signature with the unrelated key and assert that ... signer, err = signature.LoadSignerFromPEMFile(testutils.KeystoreDir+"/timestamp_key", crypto.SHA256, cryptoutils.SkipPassword) assert.NoError(t, err) - - // Append a new signature with the unrelated key and assert that ... targets.ClearSignatures() + assert.Equal(t, 0, len(targets.Signatures)) timestampSig, err := targets.Sign(signer) assert.NoError(t, err) // ... there now is only one signature, assert.Equal(t, 1, len(targets.Signatures)) // ... valid for that key. - assert.NotEmpty(t, root.Signed.Roles[TIMESTAMP].KeyIDs) - timestampKeyID := root.Signed.Roles[TIMESTAMP].KeyIDs[0] timestampKey := root.Signed.Keys[timestampKeyID] timestampPublicKey, err := timestampKey.ToPublicKey() assert.NoError(t, err) - timestampHash := crypto.Hash(0) - if timestampKey.Type != KeyTypeEd25519 { - timestampHash = crypto.SHA256 - } + timestampHash := crypto.SHA256 timestampVerifier, err := signature.LoadVerifier(timestampPublicKey, timestampHash) assert.NoError(t, err) err = timestampVerifier.VerifySignature(bytes.NewReader(timestampSig.Signature), bytes.NewReader(data)) assert.NoError(t, err) - // TODO: should fail - targetsVerifier.VerifySignature(bytes.NewReader(timestampSig.Signature), bytes.NewReader(data)) - assert.NoError(t, err) + err = targetsVerifier.VerifySignature(bytes.NewReader(timestampSig.Signature), bytes.NewReader(data)) + assert.ErrorContains(t, err, "crypto/rsa: verification error") } diff --git a/metadata/metadata_test.go b/metadata/metadata_test.go index 012eac15..a92ac611 100644 --- a/metadata/metadata_test.go +++ b/metadata/metadata_test.go @@ -12,7 +12,6 @@ package metadata import ( - "crypto" "crypto/ed25519" "crypto/sha256" "encoding/json" @@ -21,24 +20,24 @@ import ( "testing" "time" - "github.com/sigstore/sigstore/pkg/signature" "github.com/stretchr/testify/assert" ) -var ( - testRootBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}") - testEmptyTargetsBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{},\"test\":\"true\",\"version\":1}}") - testSnapshotBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"snapshot\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"targets.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}") - testTimestampBytesWithUnrecognizedField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"timestamp\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"snapshot.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}") - testRootGenericMetadta = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"version\":1},\"test\":\"true\"}") - testTargetsFileCustomField = []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{\"testTarget\":{\"custom\":{\"test\":true},\"hashes\":{},\"length\":0}},\"version\":1}}") - testRootBytes = []byte("{\"signatures\":[{\"keyid\":\"roothash\",\"sig\":\"1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee\"}],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{\"roothash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubrootval\"},\"scheme\":\"ed25519\"},\"snapshothash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubsval\"},\"scheme\":\"ed25519\"},\"targetshash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubtrval\"},\"scheme\":\"ed25519\"},\"timestamphash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubtmval\"},\"scheme\":\"ed25519\"}},\"roles\":{\"root\":{\"keyids\":[\"roothash\"],\"threshold\":1},\"snapshot\":{\"keyids\":[\"snapshothash\"],\"threshold\":1},\"targets\":{\"keyids\":[\"targetshash\"],\"threshold\":1},\"timestamp\":{\"keyids\":[\"timestamphash\"],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"version\":1}}") -) +var testRootBytes = []byte("{\"signatures\":[{\"keyid\":\"roothash\",\"sig\":\"1307990e6ba5ca145eb35e99182a9bec46531bc54ddf656a602c780fa0240dee\"}],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{\"roothash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubrootval\"},\"scheme\":\"ed25519\"},\"snapshothash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubsval\"},\"scheme\":\"ed25519\"},\"targetshash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubtrval\"},\"scheme\":\"ed25519\"},\"timestamphash\":{\"keytype\":\"ed25519\",\"keyval\":{\"public\":\"pubtmval\"},\"scheme\":\"ed25519\"}},\"roles\":{\"root\":{\"keyids\":[\"roothash\"],\"threshold\":1},\"snapshot\":{\"keyids\":[\"snapshothash\"],\"threshold\":1},\"targets\":{\"keyids\":[\"targetshash\"],\"threshold\":1},\"timestamp\":{\"keyids\":[\"timestamphash\"],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"version\":1}}") const TEST_REPOSITORY_DATA = "../testutils/repository_data/repository/metadata" var fixedExpire = time.Date(2030, 8, 15, 14, 30, 45, 100, time.UTC) +func getSignatureByKeyID(signatures []Signature, keyID string) HexBytes { + for _, sig := range signatures { + if sig.KeyID == keyID { + return sig.Signature + } + } + return []byte{} +} + func TestDefaultValuesRoot(t *testing.T) { // without setting expiration meta := Root() @@ -363,25 +362,25 @@ func TestUnrecognizedFieldRolesSigned(t *testing.T) { root.Signed.UnrecognizedFields = testUnrecognizedField rootJSON, err := root.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, testRootBytesWithUnrecognizedField, rootJSON) + assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}"), rootJSON) targets := Targets(fixedExpire) targets.Signed.UnrecognizedFields = testUnrecognizedField targetsJSON, err := targets.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, testEmptyTargetsBytesWithUnrecognizedField, targetsJSON) + assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{},\"test\":\"true\",\"version\":1}}"), targetsJSON) snapshot := Snapshot(fixedExpire) snapshot.Signed.UnrecognizedFields = testUnrecognizedField snapshotJSON, err := snapshot.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, testSnapshotBytesWithUnrecognizedField, snapshotJSON) + assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"snapshot\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"targets.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}"), snapshotJSON) timestamp := Timestamp(fixedExpire) timestamp.Signed.UnrecognizedFields = testUnrecognizedField timestampJSON, err := timestamp.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, testTimestampBytesWithUnrecognizedField, timestampJSON) + assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"timestamp\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"meta\":{\"snapshot.json\":{\"version\":1}},\"spec_version\":\"1.0.31\",\"test\":\"true\",\"version\":1}}"), timestampJSON) } func TestUnrecognizedFieldGenericMetadata(t *testing.T) { // fixed expire @@ -395,7 +394,7 @@ func TestUnrecognizedFieldGenericMetadata(t *testing.T) { root.UnrecognizedFields = testUnrecognizedField rootJSON, err := root.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, testRootGenericMetadta, rootJSON) + assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"root\",\"consistent_snapshot\":true,\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"keys\":{},\"roles\":{\"root\":{\"keyids\":[],\"threshold\":1},\"snapshot\":{\"keyids\":[],\"threshold\":1},\"targets\":{\"keyids\":[],\"threshold\":1},\"timestamp\":{\"keyids\":[],\"threshold\":1}},\"spec_version\":\"1.0.31\",\"version\":1},\"test\":\"true\"}"), rootJSON) } func TestTargetFilesCustomField(t *testing.T) { // custom JSON to test @@ -413,7 +412,7 @@ func TestTargetFilesCustomField(t *testing.T) { targets.Signed.Targets["testTarget"] = targetFile targetsJSON, err := targets.ToBytes(false) assert.NoError(t, err) - assert.Equal(t, testTargetsFileCustomField, targetsJSON) + assert.Equal(t, []byte("{\"signatures\":[],\"signed\":{\"_type\":\"targets\",\"expires\":\"2030-08-15T14:30:45.0000001Z\",\"spec_version\":\"1.0.31\",\"targets\":{\"testTarget\":{\"custom\":{\"test\":true},\"hashes\":{},\"length\":0}},\"version\":1}}"), targetsJSON) } func TestFromBytes(t *testing.T) { @@ -568,22 +567,6 @@ func TestToFile(t *testing.T) { } -func TestSign(t *testing.T) { - _, key, err := ed25519.GenerateKey(nil) - assert.NoError(t, err) - - signer, err := signature.LoadSigner(key, crypto.Hash(0)) - assert.NoError(t, err) - - root := Root(fixedExpire) - assert.Empty(t, root.Signatures) - sg, err := root.Sign(signer) - assert.NoError(t, err) - - assert.NotEmpty(t, root.Signatures) - assert.Equal(t, sg, &root.Signatures[0]) -} - func TestVerifyDelegate(t *testing.T) { root := Root(fixedExpire) err := root.VerifyDelegate("test", root)