diff --git a/dev-requirements.txt b/dev-requirements.txt index 8281097..4d353ec 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -4,6 +4,6 @@ cryptography==2.3 pynacl==1.2.1 pyasn1==0.4.4 pycrypto==2.6.1 ---editable git://github.com/awwad/tuf.git@develop#egg=tuf +--editable git://github.com/awwad/tuf.git@remove_outdated_expiration_checks#egg=tuf --editable . tox==3.1.2 diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.der b/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.der index d836c76..5c4965d 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.json b/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.json index 8614ec3..252e865 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.json @@ -3,7 +3,7 @@ { "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", "method": "ed25519", - "sig": "263a6d873455bac478366d92edc04cac55cc0e545b5f4249cf696254263d58de6a225446ce96725bccb83ffdaab548fcd89cb790020039ef336fb422364c1800" + "sig": "ee8c2399a95889c3db401200f5607d85b510427ee0e3905fd9ee91c0159952f6786eb02ff6b46fb33373043ab2f0e5637277ea0406b229010b2d4ecb45da0508" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "targets": {}, "version": 1 } diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive.zip b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive.zip index f2fb767..4b1e12a 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive.zip and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive.zip differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.der index 1e9e82a..f5c5af2 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.json index 790a3a4..3f76868 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/root.json @@ -3,7 +3,7 @@ { "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", "method": "ed25519", - "sig": "e9855e5171934d56a78033cead3dc217d6df3730f9c668742346a4e66f0d1141fe7283a21964e0c35163e76b6103e36a04d44f1b0799fe34af45c65f32f38b09" + "sig": "2ab82986eb585c970cd972cf647a7d98f0c8d44744f091d19821edf2dd746c3b56d0dc777b364d1b383503ff44bdbe33ce1443576117c816bb1c17b6f2240e00" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "keys": { "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6": { "keyid_hash_algorithms": [ @@ -24,6 +24,16 @@ "public": "99ef8790687ca252c4677a80a34e401efb7e17ccdf9b0fcb5f1bc3260c432cb9" } }, + "79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "5d7750b208dfc7ade8f6106b9c3fa25162d5a184f302161e429f19a79e66a908" + } + }, "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc": { "keyid_hash_algorithms": [ "sha256", @@ -56,6 +66,12 @@ } }, "roles": { + "Timeserver": { + "keyids": [ + "79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e" + ], + "threshold": 1 + }, "root": { "keyids": [ "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2" diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.der index ff0488e..58bff46 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.der +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.der @@ -1,4 +1,5 @@ -0֠f{' XV0 targets.der=root.derw'0% - k8} -"Lc~rI9A9i0g <=3_6T`GࡍY^SkVx -@*Ed5[{%UYQ)'gH\ǃL8 s|jz&j \ No newline at end of file +0֠fXV0 targets.der=root.derw'0% + өq#Q;rJޕRﻁi0g <=3_6T`GࡍY^SkVx +@(ƄR+C ++Octp +jyD?A{_cNzRÛ0\ \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.json index 7623663..6bdb60f 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/snapshot.json @@ -3,18 +3,18 @@ { "keyid": "f93cfcf33d335ff43654ec6047e0a18dd5595ee3de53136b94c9c756788a0f97", "method": "ed25519", - "sig": "7606de7a3cb4d899755d8fe085f8834a356ca81b65814e89aa5062faa78360ff12b9977825fa9e14baf3daf63c4da2c354ec0fe233a98d3aac63d5758caab60e" + "sig": "ac9265b8022216662d9041696260caa82a1b4a200b0ecd6f98a31a4a81bc883162462e9ea32ea30cd1ae332aff7f239414ca55923bb9a83a88402b028acf5700" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "meta": { "root.json": { "hashes": { - "sha256": "2a6db46564a0fbc905bf7a36eddc172f1ce3a52871f18f2594e5160b2321e62d" + "sha256": "7098bc863d8f04e1305ed28aa08b35d05be0f507e6b3d52a606cc6bf6e871006" }, - "length": 2120, + "length": 2259, "version": 1 }, "targets.json": { diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.der index d836c76..5c4965d 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.json index 8614ec3..252e865 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/targets.json @@ -3,7 +3,7 @@ { "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", "method": "ed25519", - "sig": "263a6d873455bac478366d92edc04cac55cc0e545b5f4249cf696254263d58de6a225446ce96725bccb83ffdaab548fcd89cb790020039ef336fb422364c1800" + "sig": "ee8c2399a95889c3db401200f5607d85b510427ee0e3905fd9ee91c0159952f6786eb02ff6b46fb33373043ab2f0e5637277ea0406b229010b2d4ecb45da0508" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "targets": {}, "version": 1 } diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.der index e1e1df6..17233db 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.json index b08013e..2625519 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/director/metadata/timestamp.json @@ -3,16 +3,16 @@ { "keyid": "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc", "method": "ed25519", - "sig": "3500dd4af7002c2a7d36c1a4b546b87979805a5c31f6038b39ca19d5d61868b5d3cc8c96c93eb44c3ed862859f45739e926626b73b7beb2d37ceeb83b32c8b0c" + "sig": "dbe5e8c1075e68b888eaa0d85cba9f97610980cf634110e0dcc558eb325f28de5129fb92d807a59a18f94637250a22c4ff76e065f9863daaad818683e5122e0d" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "114817f21566942dbcdafe97e3d1aca1660db86d8920a872c65b76d9890409de" + "sha256": "d3bc22745f0ad4c6f12df987346a3f5a29f024d899c16d23f25adb401d618cfa" }, "length": 594, "version": 1 diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.der index 6fea55f..5c932fb 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.json index cd2cd95..4fe725a 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/root.json @@ -1,9 +1,9 @@ { "signatures": [ { - "keyid": "94c836f0c45168f0a437eef0e487b910f58db4d462ae457b5730a4487130f290", + "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", "method": "ed25519", - "sig": "bdbbbfa6b75e98bbc5f04549f1b181e39cc7c8ad8bd86a41c061825e01ed5d2cf1a294cb45f7441cb15fe0302264a98c7813af699c12ba25ccee08878436c20b" + "sig": "e47bc67e9d4433ad91f7e3b22b09752c735ba7f84a7812f9a6be086cdad70cbd8b93d68cea3ed94beb514aa099740046c352486dade1c60f68a3a24ce427e900" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "keys": { "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a": { "keyid_hash_algorithms": [ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.der index 7f5ca7f..be72d96 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.json index d5ce843..fb412ae 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/snapshot.json @@ -3,18 +3,18 @@ { "keyid": "aaf05f8d054f8068bf6cb46beed7c824e2560802df462fc8681677586582ca99", "method": "ed25519", - "sig": "8cb2bff8f52a5aed8979a9c1ebfa047fb4ee58b63830037593bd240ceaafbae274c80c9d59aa3b6fba2bdd6de3c535e3230de2a51509042ca2f7d61523065709" + "sig": "3fd1bdc6b6f70fca7063a39a063da63f13bd84388e374c566732faad4988cf1028cd8c02668acf08a22bc6c955a6e1467df9bea46328873e0b4cd8529746c108" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "root.json": { "hashes": { - "sha256": "69385580f90dcd47d7d309070f65515188d392b41416d1efeb330978b77e4a96" + "sha256": "33f29c8ffce9b7ea3095a15000b9265d69e2498a9beb29f5cecc0fb3b7494a08" }, - "length": 2120, + "length": 2259, "version": 1 }, "targets.json": { diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.der index 8e2204a..ad3d257 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.json index 9275521..ee1c00e 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/targets.json @@ -3,7 +3,7 @@ { "keyid": "c24b457b2ca4b3c2f415efdbbebb914a0d05c5345b9889bda044362589d6f596", "method": "ed25519", - "sig": "aa5c4bd41dbb8bcf5fdc6fd44ec6b42998488fb1849cc9634e58e514dc5f00f7a59e75216db325f07bfdaba72558a9a4dcfe694f76c8e9af2980477a2893b208" + "sig": "6c300b24ffb94f9d1d3465e3e9a877a359c5e5316e3edfd86154eeee08503e111fa23c8b7ca8af2af74747e701272999e61b4930b98a15a41e4a6d20e781490f" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "targets": { "/BCU1.0.txt": { "hashes": { diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.der b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.der index 78e17e8..93282ab 100644 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.der and b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.der differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.json b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.json index 1a34ad6..eeeaea0 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/full_metadata_archive/imagerepo/metadata/timestamp.json @@ -3,16 +3,16 @@ { "keyid": "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a", "method": "ed25519", - "sig": "8aa14b371d10f81a5f4232967d682ef254f5a92221b5cd224811e053d5a8bd99cc1298984c284580684a958eec2f40a6eaf0d8756bd950e5b3714736befda805" + "sig": "eb505991b63a7dddd153edd4e1a1ee00d46caefbfaf39ec85cf0b96c681f8f33b25666bb101b7f0e7a614dbd8c9eaa97986f5cb5e2873cc1213cafa2d1f59e0c" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "d37a3f9b41bd7ad4c87bc978f0341cbeb081bdee0891f087f33d34963c565e16" + "sha256": "d88bd443c813a54a029527f70e8dc8c7266c20a02c1a07d2d3227c51c7f5c669" }, "length": 594, "version": 1 diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/director_targets.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/director_targets.json new file mode 100644 index 0000000..252e865 --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/director_targets.json @@ -0,0 +1,19 @@ +{ + "signatures": [ + { + "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", + "method": "ed25519", + "sig": "ee8c2399a95889c3db401200f5607d85b510427ee0e3905fd9ee91c0159952f6786eb02ff6b46fb33373043ab2f0e5637277ea0406b229010b2d4ecb45da0508" + } + ], + "signed": { + "_type": "Targets", + "delegations": { + "keys": {}, + "roles": [] + }, + "expires": "2038-01-18T03:14:19Z", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive.zip b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive.zip new file mode 100644 index 0000000..e631b5c Binary files /dev/null and b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive.zip differ diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/root.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/root.json new file mode 100644 index 0000000..1acc7af --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/root.json @@ -0,0 +1,92 @@ +{ + "signatures": [ + { + "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", + "method": "ed25519", + "sig": "b7812100db40cf8348cb7643786f5b4a77173f8586cca219baef5e6f4af4d459e3eb01b33636ecee51ec02c142d52be409b3ae1c372145a1341750f8ed4d730e" + } + ], + "signed": { + "_type": "Root", + "compression_algorithms": [ + "gz" + ], + "consistent_snapshot": false, + "expires": "2038-01-18T03:14:19Z", + "keys": { + "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "99ef8790687ca252c4677a80a34e401efb7e17ccdf9b0fcb5f1bc3260c432cb9" + } + }, + "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "d1ab5126fd6f0e30944910e81c0448044dfe9d5a39f478212b2afa913bb7ca7c" + } + }, + "f93cfcf33d335ff43654ec6047e0a18dd5595ee3de53136b94c9c756788a0f97": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "228342cc8b78a65b8840ef5691a693d8c368e053a7e8e8f85faf7c83eff1e1d2" + } + }, + "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "f3b4c231520580eca92e17ae1581a708f606f72d43cc200af493afeec22a5e79" + } + } + }, + "roles": { + "Timeserver": { + "keyids": [ + "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc" + ], + "threshold": 1 + }, + "root": { + "keyids": [ + "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "f93cfcf33d335ff43654ec6047e0a18dd5595ee3de53136b94c9c756788a0f97" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc" + ], + "threshold": 1 + } + }, + "version": 2 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/snapshot.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/snapshot.json new file mode 100644 index 0000000..58de307 --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/snapshot.json @@ -0,0 +1,26 @@ +{ + "signatures": [ + { + "keyid": "f93cfcf33d335ff43654ec6047e0a18dd5595ee3de53136b94c9c756788a0f97", + "method": "ed25519", + "sig": "48264bae99b07b6c2cc3a9112264cd0f2d2e4cee94e1ab7a3160ca579c0aab13452b8a70b43b3b5a746d1d34723695aaace087e99c84d5ad35d2fd1d658e1902" + } + ], + "signed": { + "_type": "Snapshot", + "expires": "2038-01-18T03:14:19Z", + "meta": { + "root.json": { + "hashes": { + "sha256": "072863a1e81e4dc4b8d19b23cfecf742ee15a7d5afc06a03dd45f63fec81849c" + }, + "length": 2259, + "version": 2 + }, + "targets.json": { + "version": 1 + } + }, + "version": 2 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/targets.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/targets.json new file mode 100644 index 0000000..252e865 --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/targets.json @@ -0,0 +1,19 @@ +{ + "signatures": [ + { + "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", + "method": "ed25519", + "sig": "ee8c2399a95889c3db401200f5607d85b510427ee0e3905fd9ee91c0159952f6786eb02ff6b46fb33373043ab2f0e5637277ea0406b229010b2d4ecb45da0508" + } + ], + "signed": { + "_type": "Targets", + "delegations": { + "keys": {}, + "roles": [] + }, + "expires": "2038-01-18T03:14:19Z", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/timestamp.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/timestamp.json new file mode 100644 index 0000000..8dbe9fe --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/director/metadata/timestamp.json @@ -0,0 +1,23 @@ +{ + "signatures": [ + { + "keyid": "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc", + "method": "ed25519", + "sig": "1c82207c253296522647abaddc3b0555945ef91833ac0e66fd79227d4c36465f3e616e00906ef9b4516bbff32bbb43d7b7d9dc0e2ff55d70401ce6480af0c700" + } + ], + "signed": { + "_type": "Timestamp", + "expires": "2038-01-18T03:14:19Z", + "meta": { + "snapshot.json": { + "hashes": { + "sha256": "b1a604f49312e9fc498c28cda12b794f8874c9069174916e0bad7ea360d2bbec" + }, + "length": 594, + "version": 2 + } + }, + "version": 2 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/root.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/root.json new file mode 100644 index 0000000..4fe725a --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/root.json @@ -0,0 +1,86 @@ +{ + "signatures": [ + { + "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", + "method": "ed25519", + "sig": "e47bc67e9d4433ad91f7e3b22b09752c735ba7f84a7812f9a6be086cdad70cbd8b93d68cea3ed94beb514aa099740046c352486dade1c60f68a3a24ce427e900" + } + ], + "signed": { + "_type": "Root", + "compression_algorithms": [ + "gz" + ], + "consistent_snapshot": false, + "expires": "2038-01-18T03:14:07Z", + "keys": { + "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "97c1112bbd9047b1fdb50dd638bfed6d0639e0dff2c1443f5593fea40e30f654" + } + }, + "94c836f0c45168f0a437eef0e487b910f58db4d462ae457b5730a4487130f290": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "f4ac8d95cfdf65a4ccaee072ba5a48e8ad6a0c30be6ffd525aec6bc078211033" + } + }, + "aaf05f8d054f8068bf6cb46beed7c824e2560802df462fc8681677586582ca99": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "497f62d80e5b892718da8788bb549bcf8369a1460ec23d6d67d0ca099a8e8f83" + } + }, + "c24b457b2ca4b3c2f415efdbbebb914a0d05c5345b9889bda044362589d6f596": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "729d9cb5f74688ef8e9a22fae1516f33ff98c7910b64bf3b66e6cfc51559840e" + } + } + }, + "roles": { + "root": { + "keyids": [ + "94c836f0c45168f0a437eef0e487b910f58db4d462ae457b5730a4487130f290" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "aaf05f8d054f8068bf6cb46beed7c824e2560802df462fc8681677586582ca99" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "c24b457b2ca4b3c2f415efdbbebb914a0d05c5345b9889bda044362589d6f596" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a" + ], + "threshold": 1 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/snapshot.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/snapshot.json new file mode 100644 index 0000000..fb412ae --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/snapshot.json @@ -0,0 +1,26 @@ +{ + "signatures": [ + { + "keyid": "aaf05f8d054f8068bf6cb46beed7c824e2560802df462fc8681677586582ca99", + "method": "ed25519", + "sig": "3fd1bdc6b6f70fca7063a39a063da63f13bd84388e374c566732faad4988cf1028cd8c02668acf08a22bc6c955a6e1467df9bea46328873e0b4cd8529746c108" + } + ], + "signed": { + "_type": "Snapshot", + "expires": "2038-01-18T03:14:07Z", + "meta": { + "root.json": { + "hashes": { + "sha256": "33f29c8ffce9b7ea3095a15000b9265d69e2498a9beb29f5cecc0fb3b7494a08" + }, + "length": 2259, + "version": 1 + }, + "targets.json": { + "version": 1 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/targets.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/targets.json new file mode 100644 index 0000000..ee1c00e --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/targets.json @@ -0,0 +1,69 @@ +{ + "signatures": [ + { + "keyid": "c24b457b2ca4b3c2f415efdbbebb914a0d05c5345b9889bda044362589d6f596", + "method": "ed25519", + "sig": "6c300b24ffb94f9d1d3465e3e9a877a359c5e5316e3edfd86154eeee08503e111fa23c8b7ca8af2af74747e701272999e61b4930b98a15a41e4a6d20e781490f" + } + ], + "signed": { + "_type": "Targets", + "delegations": { + "keys": {}, + "roles": [] + }, + "expires": "2038-01-18T03:14:07Z", + "targets": { + "/BCU1.0.txt": { + "hashes": { + "sha256": "fb0aa5699a4e7b68009fed6b094ecb00c3ad5670921be1b902b72a23cd4675b1", + "sha512": "0b0bb00bccf7bdad519d0a0af2794c945bd51ebdbc79f9616f0e3903b32f4ce2d5b250ab1bc2d34194bacf720b4f0aed361ef8d59ac72b1bc19e3a223a5e87cd" + }, + "length": 15 + }, + "/BCU1.1.txt": { + "hashes": { + "sha256": "1eb6fa5c6bb606c5326d6ef0ff05f5fcefde4e50c7daea530978090778b38bf4", + "sha512": "9727058c2ba828fdd2fc5ae02f52c10e47404283f92df3539989e2ada3cf7e85a9772faed1bd0bad3fc2bd8f6e5d15b976b8e832dd46874be72b994bc57a62a0" + }, + "length": 18 + }, + "/BCU1.2.txt": { + "hashes": { + "sha256": "42914dc1509923fc83b6945cbaaec193a22077ae3bb799e84b900570715fcb5a", + "sha512": "f213f63b79b05e3ea2045ffe198ab75a993ca5b2709a2e1eac5f18a1a6be1b5eb6af9964b78d388b404414e296b046228f9b68eb75db684eed75b509518a77a5" + }, + "length": 18 + }, + "/INFO1.0.txt": { + "hashes": { + "sha256": "e116d4ef5a2f2dbba9a61970a25cab3e6695418e3dbfa71071e4d07aebb1f083", + "sha512": "7cfa230b2ad2290d38d0da9f0320c1de0dcc9acc40a74154d8f6461c9acb63e7a41a34034b6d84fed6220e1a42afbaa0846efcfc85e1d83c5174f1f8d88d2694" + }, + "length": 18 + }, + "/TCU1.0.txt": { + "hashes": { + "sha256": "c0f997636d40ef418697e85add2e3e6f994592de0c4d90ffe0f86e177281b0dc", + "sha512": "87e3d4f40b43f457e507c81e0caa306893ecf4eb65c28a8ef4a5e5e66323c460c500a7cb9489221eb8bcd2eb5b7e848dcf8c631518289fa07e629c4ffcf8e686" + }, + "length": 16 + }, + "/TCU1.1.txt": { + "hashes": { + "sha256": "56d7cd56a85e34e40d005e1f79c0e95d6937d5528ac0b301dbe68d57e03a5c21", + "sha512": "94d7419b8606103f363aa17feb875575a978df8e88038ea284ff88d90e534eaa7218040384b19992cc7866f5eca803e1654c9ccdf3b250d6198b3c4731216db4" + }, + "length": 17 + }, + "/TCU1.2.txt": { + "hashes": { + "sha256": "fbc8fa01df33f30833428be0fb20edfaafa444ed23d020e3cbc9c60cff167288", + "sha512": "c7c3924d33804eca1d691c5fe61bb965646bf9b6225ce1f040dcde81ce0fc26f4be323f4995e0dee35a847fdbb6efe5a8c8e248e07d1728af0b4cc6fb3179d38" + }, + "length": 17 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/timestamp.json b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/timestamp.json new file mode 100644 index 0000000..eeeaea0 --- /dev/null +++ b/samples/metadata_samples_long_expiry/timeserver_key_rotated/full_metadata_archive/imagerepo/metadata/timestamp.json @@ -0,0 +1,23 @@ +{ + "signatures": [ + { + "keyid": "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a", + "method": "ed25519", + "sig": "eb505991b63a7dddd153edd4e1a1ee00d46caefbfaf39ec85cf0b96c681f8f33b25666bb101b7f0e7a614dbd8c9eaa97986f5cb5e2873cc1213cafa2d1f59e0c" + } + ], + "signed": { + "_type": "Timestamp", + "expires": "2038-01-18T03:14:07Z", + "meta": { + "snapshot.json": { + "hashes": { + "sha256": "d88bd443c813a54a029527f70e8dc8c7266c20a02c1a07d2d3227c51c7f5c669" + }, + "length": 594, + "version": 1 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.der index 09869c3..5d7ac88 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.json index f883915..99b85e4 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.json @@ -3,7 +3,7 @@ { "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", "method": "ed25519", - "sig": "e97a2e9d819555cc2c8af799cb2020857a0217ca5246d3365e3d881d9f53aa94ded9ef6c64caa8b606728b52451555c3a79500c266163b9a66933bde7012c302" + "sig": "22c402ecf09ecd92ac01e04dca09dfa3b02675d3713ace97993a262bcbf5e566c40bc92bdf2d769c096e9308375dffc06ae4fef29e6e9badae59eec58ddd2701" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "targets": { "/TCU1.1.txt": { "custom": { diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive.zip b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive.zip index acc2e4b..a6020a6 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive.zip and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive.zip differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.der index 1e9e82a..f5c5af2 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.json index 790a3a4..3f76868 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/root.json @@ -3,7 +3,7 @@ { "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", "method": "ed25519", - "sig": "e9855e5171934d56a78033cead3dc217d6df3730f9c668742346a4e66f0d1141fe7283a21964e0c35163e76b6103e36a04d44f1b0799fe34af45c65f32f38b09" + "sig": "2ab82986eb585c970cd972cf647a7d98f0c8d44744f091d19821edf2dd746c3b56d0dc777b364d1b383503ff44bdbe33ce1443576117c816bb1c17b6f2240e00" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "keys": { "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6": { "keyid_hash_algorithms": [ @@ -24,6 +24,16 @@ "public": "99ef8790687ca252c4677a80a34e401efb7e17ccdf9b0fcb5f1bc3260c432cb9" } }, + "79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "5d7750b208dfc7ade8f6106b9c3fa25162d5a184f302161e429f19a79e66a908" + } + }, "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc": { "keyid_hash_algorithms": [ "sha256", @@ -56,6 +66,12 @@ } }, "roles": { + "Timeserver": { + "keyids": [ + "79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e" + ], + "threshold": 1 + }, "root": { "keyids": [ "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2" diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.der index c5a2945..958d6ea 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.der +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.der @@ -1,4 +1,3 @@ -0֠f{' XV0 targets.der=root.derw'0% - k8} -"Lc~rI9A9i0g <=3_6T`GࡍY^SkVx -@dK-D5rmՆԋ ղfAtͫE@6y% -!^ɂ \ No newline at end of file +0֠fXV0 targets.der=root.derw'0% + өq#Q;rJޕRﻁi0g <=3_6T`GࡍY^SkVx +@M&~qm%L|*E?Кd,bg*KE/W鍲o*hJ Ǻ \ No newline at end of file diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.json index 49b5157..f073cdf 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.json @@ -3,18 +3,18 @@ { "keyid": "f93cfcf33d335ff43654ec6047e0a18dd5595ee3de53136b94c9c756788a0f97", "method": "ed25519", - "sig": "701d882716b54c0953d6811e0d4e5cfe788d75f4d0c425af9b2ec9bd8e3abec3f2ac707575680601a1b983b11aa290ec7add7070734a6a05b2a1117a9a31320c" + "sig": "3432f7fdfa51c050929c1eefc9812ed7dc18b5dcc1fd318c48b0a8cc4654b74905cbbbee947ea6bd8e7aabd06df9cdabc4791a2e0201e69a5f8cb7a072676b0d" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "meta": { "root.json": { "hashes": { - "sha256": "2a6db46564a0fbc905bf7a36eddc172f1ce3a52871f18f2594e5160b2321e62d" + "sha256": "7098bc863d8f04e1305ed28aa08b35d05be0f507e6b3d52a606cc6bf6e871006" }, - "length": 2120, + "length": 2259, "version": 1 }, "targets.json": { diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.der index 09869c3..5d7ac88 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.json index f883915..99b85e4 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/targets.json @@ -3,7 +3,7 @@ { "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", "method": "ed25519", - "sig": "e97a2e9d819555cc2c8af799cb2020857a0217ca5246d3365e3d881d9f53aa94ded9ef6c64caa8b606728b52451555c3a79500c266163b9a66933bde7012c302" + "sig": "22c402ecf09ecd92ac01e04dca09dfa3b02675d3713ace97993a262bcbf5e566c40bc92bdf2d769c096e9308375dffc06ae4fef29e6e9badae59eec58ddd2701" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "targets": { "/TCU1.1.txt": { "custom": { diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.der index 5179294..8cd2b8d 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.json index 5fb7a72..0829bc1 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/timestamp.json @@ -3,16 +3,16 @@ { "keyid": "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc", "method": "ed25519", - "sig": "2e170caedf043a5df86f731d6b60eed84766ee66a9cb6a3ea42423a7a8d64dfedf1dec0c7fc1b56cd6479bfcc57c6f5861ded88446aaebb9f88b016020dd2603" + "sig": "064409a87ed79b2bda498112382379513bf80812312d49c571cfd7f17e9d6e39a8f5c292b79033e9a89c225a74b9fd7b9766b402ae890d73b77c0779d82e2503" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "d6a27db7727136afedc07d1e34bb078a6436c6779fa13d324942f135e04d0710" + "sha256": "33f214adde1a77ff7c3e1f2c7ccab0bf9fcb6faf6dbf63c6724dc856e1c47984" }, "length": 594, "version": 2 diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.der index 6fea55f..5c932fb 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.json index cd2cd95..4fe725a 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/root.json @@ -1,9 +1,9 @@ { "signatures": [ { - "keyid": "94c836f0c45168f0a437eef0e487b910f58db4d462ae457b5730a4487130f290", + "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", "method": "ed25519", - "sig": "bdbbbfa6b75e98bbc5f04549f1b181e39cc7c8ad8bd86a41c061825e01ed5d2cf1a294cb45f7441cb15fe0302264a98c7813af699c12ba25ccee08878436c20b" + "sig": "e47bc67e9d4433ad91f7e3b22b09752c735ba7f84a7812f9a6be086cdad70cbd8b93d68cea3ed94beb514aa099740046c352486dade1c60f68a3a24ce427e900" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "keys": { "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a": { "keyid_hash_algorithms": [ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.der index 7f5ca7f..be72d96 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.json index d5ce843..fb412ae 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/snapshot.json @@ -3,18 +3,18 @@ { "keyid": "aaf05f8d054f8068bf6cb46beed7c824e2560802df462fc8681677586582ca99", "method": "ed25519", - "sig": "8cb2bff8f52a5aed8979a9c1ebfa047fb4ee58b63830037593bd240ceaafbae274c80c9d59aa3b6fba2bdd6de3c535e3230de2a51509042ca2f7d61523065709" + "sig": "3fd1bdc6b6f70fca7063a39a063da63f13bd84388e374c566732faad4988cf1028cd8c02668acf08a22bc6c955a6e1467df9bea46328873e0b4cd8529746c108" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "root.json": { "hashes": { - "sha256": "69385580f90dcd47d7d309070f65515188d392b41416d1efeb330978b77e4a96" + "sha256": "33f29c8ffce9b7ea3095a15000b9265d69e2498a9beb29f5cecc0fb3b7494a08" }, - "length": 2120, + "length": 2259, "version": 1 }, "targets.json": { diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.der index 8e2204a..ad3d257 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.json index 9275521..ee1c00e 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/targets.json @@ -3,7 +3,7 @@ { "keyid": "c24b457b2ca4b3c2f415efdbbebb914a0d05c5345b9889bda044362589d6f596", "method": "ed25519", - "sig": "aa5c4bd41dbb8bcf5fdc6fd44ec6b42998488fb1849cc9634e58e514dc5f00f7a59e75216db325f07bfdaba72558a9a4dcfe694f76c8e9af2980477a2893b208" + "sig": "6c300b24ffb94f9d1d3465e3e9a877a359c5e5316e3edfd86154eeee08503e111fa23c8b7ca8af2af74747e701272999e61b4930b98a15a41e4a6d20e781490f" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "targets": { "/BCU1.0.txt": { "hashes": { diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.der index 78e17e8..93282ab 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.der differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.json b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.json index 1a34ad6..eeeaea0 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/imagerepo/metadata/timestamp.json @@ -3,16 +3,16 @@ { "keyid": "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a", "method": "ed25519", - "sig": "8aa14b371d10f81a5f4232967d682ef254f5a92221b5cd224811e053d5a8bd99cc1298984c284580684a958eec2f40a6eaf0d8756bd950e5b3714736befda805" + "sig": "eb505991b63a7dddd153edd4e1a1ee00d46caefbfaf39ec85cf0b96c681f8f33b25666bb101b7f0e7a614dbd8c9eaa97986f5cb5e2873cc1213cafa2d1f59e0c" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "d37a3f9b41bd7ad4c87bc978f0341cbeb081bdee0891f087f33d34963c565e16" + "sha256": "d88bd443c813a54a029527f70e8dc8c7266c20a02c1a07d2d3227c51c7f5c669" }, "length": 594, "version": 1 diff --git a/tests/test_data/director_metadata/root.json b/tests/test_data/director_metadata/root.json index 790a3a4..3f76868 100644 --- a/tests/test_data/director_metadata/root.json +++ b/tests/test_data/director_metadata/root.json @@ -3,7 +3,7 @@ { "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", "method": "ed25519", - "sig": "e9855e5171934d56a78033cead3dc217d6df3730f9c668742346a4e66f0d1141fe7283a21964e0c35163e76b6103e36a04d44f1b0799fe34af45c65f32f38b09" + "sig": "2ab82986eb585c970cd972cf647a7d98f0c8d44744f091d19821edf2dd746c3b56d0dc777b364d1b383503ff44bdbe33ce1443576117c816bb1c17b6f2240e00" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:19Z", "keys": { "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6": { "keyid_hash_algorithms": [ @@ -24,6 +24,16 @@ "public": "99ef8790687ca252c4677a80a34e401efb7e17ccdf9b0fcb5f1bc3260c432cb9" } }, + "79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "5d7750b208dfc7ade8f6106b9c3fa25162d5a184f302161e429f19a79e66a908" + } + }, "da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc": { "keyid_hash_algorithms": [ "sha256", @@ -56,6 +66,12 @@ } }, "roles": { + "Timeserver": { + "keyids": [ + "79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e" + ], + "threshold": 1 + }, "root": { "keyids": [ "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2" diff --git a/tests/test_data/image_repo_metadata/root.json b/tests/test_data/image_repo_metadata/root.json index cd2cd95..4fe725a 100644 --- a/tests/test_data/image_repo_metadata/root.json +++ b/tests/test_data/image_repo_metadata/root.json @@ -1,9 +1,9 @@ { "signatures": [ { - "keyid": "94c836f0c45168f0a437eef0e487b910f58db4d462ae457b5730a4487130f290", + "keyid": "fdba7eaa358fa5a8113a789f60c4a6ce29c4478d8d8eff3e27d1d77416696ab2", "method": "ed25519", - "sig": "bdbbbfa6b75e98bbc5f04549f1b181e39cc7c8ad8bd86a41c061825e01ed5d2cf1a294cb45f7441cb15fe0302264a98c7813af699c12ba25ccee08878436c20b" + "sig": "e47bc67e9d4433ad91f7e3b22b09752c735ba7f84a7812f9a6be086cdad70cbd8b93d68cea3ed94beb514aa099740046c352486dade1c60f68a3a24ce427e900" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "keys": { "6fcd9a928358ad8ca7e946325f57ec71d50cb5977a8d02c5ab0de6765fef040a": { "keyid_hash_algorithms": [ diff --git a/tests/test_secondary.py b/tests/test_secondary.py index a90ee1b..5a83788 100644 --- a/tests/test_secondary.py +++ b/tests/test_secondary.py @@ -19,6 +19,7 @@ import shutil import hashlib import iso8601 +import time from six.moves.urllib.error import URLError @@ -31,6 +32,7 @@ import uptane.clients.secondary as secondary import uptane.common # verify sigs, create client dir structure, convert key import uptane.encoding.asn1_codec as asn1_codec +import uptane.services.timeserver as timeserver from uptane.encoding.asn1_codec import DATATYPE_TIME_ATTESTATION from uptane.encoding.asn1_codec import DATATYPE_ECU_MANIFEST @@ -55,17 +57,18 @@ TEMP_CLIENT_DIRS = [ os.path.join(TEST_DATA_DIR, 'temp_test_secondary0'), os.path.join(TEST_DATA_DIR, 'temp_test_secondary1'), - os.path.join(TEST_DATA_DIR, 'temp_test_secondary2')] + os.path.join(TEST_DATA_DIR, 'temp_test_secondary2'), + os.path.join(TEST_DATA_DIR, 'temp_test_secondary3')] # I'll initialize these in the __init__ test, and use this for the simple # non-damaging tests so as to avoid creating objects all over again. -secondary_instances = [None, None, None] +secondary_instances = [None, None, None, None] # Changing these values would require producing new signed test data from the # Timeserver (in the case of nonce) or a Secondary (in the case of the others). nonce = 5 -vins = ['democar', 'democar', '000'] -ecu_serials = ['TCUdemocar', '00000', '00000'] +vins = ['democar', 'democar', '000', 'democar'] +ecu_serials = ['TCUdemocar', '00000', '00000', 'TCUdemocar'] # Set starting firmware fileinfo (that this ECU had coming from the factory) # It will serve as the initial firmware state for the Secondary clients. @@ -349,7 +352,7 @@ def test_01_init(self): - # Try initializing three Secondaries, expecting the three calls to work. + # Try initializing four Secondaries, expecting the four calls to work. # Save the instances for future tests as class variables to save time and # code. @@ -360,13 +363,13 @@ def test_01_init(self): # it work for these tests. - # Initialize three clients and perform checks on each of them. + # Initialize four clients and perform checks on each of them. for i in range(0, len(TEMP_CLIENT_DIRS)): client_dir = TEMP_CLIENT_DIRS[i] ecu_serial = ecu_serials[i] vin = vins[i] - # Try initializing each of three secondaries, expecting these calls to + # Try initializing each of four secondaries, expecting these calls to # work. Save the instances for future tests as elements in a module list # variable(secondary_instances) to save time and code. tuf.conf.repository_directory = client_dir @@ -445,7 +448,7 @@ def test_10_nonce_rotation(self): - change_nonce() - set_nonce_as_sent() """ - # We'll just test one of the three client instances, since it shouldn't + # We'll just test one of the four client instances, since it shouldn't # make a difference. instance = secondary_instances[0] @@ -468,7 +471,7 @@ def test_20_update_time(self): Tests uptane.clients.secondary.Secondary::update_time() """ - # We'll just test one of the three client instances, since it shouldn't + # We'll just test one of the four client instances, since it shouldn't # make a difference. instance = secondary_instances[0] @@ -571,7 +574,7 @@ def test_25_generate_signed_ecu_manifest(self): Tests uptane.clients.secondary.Secondary::generate_signed_ecu_manifest() """ - # We'll just test one of the three client instances, since it shouldn't + # We'll just test one of the four client instances, since it shouldn't # make a difference. ecu_manifest = secondary_instances[0].generate_signed_ecu_manifest() @@ -610,10 +613,11 @@ def test_40_process_metadata(self): """ Tests uptane.clients.secondary.Secondary::process_metadata() - Tests three clients: + Tests four clients: - secondary_instances[0]: an update is provided in Director metadata - secondary_instances[1]: no update is provided in Director metadata - secondary_instances[2]: no Director metadata can be retrieved + - secondary_instances[3]: an update is provided in Director metadata (same as 0) """ # --- Test this test module's setup (defensive) @@ -678,7 +682,7 @@ def test_40_process_metadata(self): '/metadata/' + role + '.' + tuf.conf.METADATA_FORMAT)) - # Verify the results of the test, which are different for the three clients. + # Verify the results of the test, which are different for the four clients. # First: Check the top-level metadata files in the client directories. @@ -707,10 +711,13 @@ def test_40_process_metadata(self): # Second: Check targets each Secondary client has been instructed to # install (and has in turn validated). - # Client 0 should have validated expected_updated_fileinfo. + # Clients 0 and 3 should have validated expected_updated_fileinfo. self.assertEqual( expected_updated_fileinfo, secondary_instances[0].validated_targets_for_this_ecu[0]) + self.assertEqual( + expected_updated_fileinfo, + secondary_instances[3].validated_targets_for_this_ecu[0]) # Clients 1 and 2 should have no validated targets. self.assertFalse(secondary_instances[1].validated_targets_for_this_ecu) @@ -751,6 +758,345 @@ def test_50_validate_image(self): + def test_90_timeserver_key_rotation(self): + ''' + This test works only in JSON mode. ASN.1/DER metadata has not been + extended here to enable Timeserver key rotation. + + Note that this test, like the rest in this test module, builds on prior + tests, and should not be run on its own. + + Use the first test Secondary instance, which has by now verified metadata. + Try updating to a later version of metadata that indicates a different + Timeserver key in the Director's Root metadata. + ''' + + if tuf.conf.METADATA_FORMAT == 'der': + print('Skipping the JSON-only test_90_timeserver_key_rotation.') + return + + instance = secondary_instances[0] + + # Since we're switching clients, we should switch the TUF override time to + # what this client thinks it should be. (We're cheating by juggling + # multiple clients in one process for testing purposes, and the TUF clock + # override is a module-level variable in tuf.conf, so it's common to all + # clients in a process.) Use the last trusted time for the instance. + tuf.conf.CLOCK_OVERRIDE = int(tuf.formats.datetime_to_unix_timestamp( + iso8601.parse_date(instance.all_valid_timeserver_times[-1]))) + + + # PREPARE an update with the timeserver key rotated. + archive_with_rotated_key = os.path.join( + SAMPLES_DIR, 'metadata_samples_long_expiry', 'timeserver_key_rotated', + 'full_metadata_archive.zip') + + initially_trusted_timeserver_keyid = \ + instance.timeserver_public_key['keyid'] + + + # CHECK INITIAL state before the test: + + # 1. There should be trusted timeserver attestations. + self.assertEqual(3, len(instance.all_valid_timeserver_times)) + + # 2. The current trusted time should be '2016-11-02T21:06:05Z' from the + # attestation in the sample metadata from prior tests. + # self.assertIsNotNone(tuf.conf.CLOCK_OVERRIDE) + self.assertEqual( + int(tuf.formats.datetime_to_unix_timestamp(iso8601.parse_date( + '2016-11-02T21:06:05Z'))), tuf.conf.CLOCK_OVERRIDE) + + # 3. The currently trusted Root metadata in the Secondary's updater for the + # Director repository should list the same Timeserver keyid as the + # Secondary has noted is the currently trusted Timeserver key's keyid. + # This should be the 79c79... key we know was in the original root + # metadata. + self.assertEqual( + initially_trusted_timeserver_keyid, + instance.updater.repositories['director'].metadata['current']['root'] + ['roles']['Timeserver']['keyids'][0]) + self.assertEqual( + '79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e', + initially_trusted_timeserver_keyid) + + + # Update to the new metadata with the new Timeserver key. + instance.process_metadata(archive_with_rotated_key) + + now_trusted_timeserver_keyid = \ + instance.timeserver_public_key['keyid'] + + + # CHECK RESULTING state: + + # 1. There should be zero trusted timeserver attestations immediately after + # rotation. + self.assertEqual(0, len(instance.all_valid_timeserver_attestations)) + + # 2. The trusted time and the TUF clock override should be 0, epoch start. + self.assertEqual( + ['1970-01-01T00:00:00Z'], instance.all_valid_timeserver_times) + self.assertEqual(0, tuf.conf.CLOCK_OVERRIDE) + + # 3. The currently trusted Root metadata in the Secondary's updater for the + # Director repository should list the same Timeserver keyid as the + # Secondary has noted is the currently trusted Timeserver key's keyid. + # This should be the da9c6... key we know is in the sample rotated + # metadata. + self.assertEqual( + now_trusted_timeserver_keyid, + instance.updater.repositories['director'].metadata['current']['root'] + ['roles']['Timeserver']['keyids'][0]) + self.assertEqual( + 'da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc', + now_trusted_timeserver_keyid) + + # For good measure, to avoid stupid mistakes in future test code changes. + # Make sure the key changed. + self.assertNotEqual( + initially_trusted_timeserver_keyid, now_trusted_timeserver_keyid) + + + + + + def test_95_timeserver_fastforward_attack(self): + ''' + This test works only in JSON mode. ASN.1/DER metadata has not been + extended here to enable Timeserver key rotation. + + This is similar to test 90, except that we'll conduct a Timeserver + fast-forward attack before rotating the Timeserver key, make sure that the + attack impairs updating, check that the failed update during the attack had + no unexpected consequences, and after performing the rotation and updating + the Secondary, confirm that the attack is resolved. + + We'll use the fourth test Secondary instance (secondary_instances[3]), + which was more or less identical to instance [0] until test 90 above. + ''' + + if tuf.conf.METADATA_FORMAT == 'der': + print('Skipping the JSON-only test_95_timeserver_fastforward_attack') + return + + instance = secondary_instances[3] + + # Since we're switching clients, we should switch the TUF override time to + # what this client thinks it should be. (We're cheating by juggling + # multiple clients in one process for testing purposes, and the TUF clock + # override is a module-level variable in tuf.conf, so it's common to all + # clients in a process.) Use the last trusted time for the instance. + tuf.conf.CLOCK_OVERRIDE = int(tuf.formats.datetime_to_unix_timestamp( + iso8601.parse_date(instance.all_valid_timeserver_times[-1]))) + + + + # CHECK INITIAL state before the attack: + + # 1. There should be 2 trusted timeserver attestations initially. + self.assertEqual(2, len(instance.all_valid_timeserver_times)) + + # 2. We would check the client's override time, but that's stored in a + # module-level variable for the whole process, and we're cheating and + # running four clients in one process, so we just reset the clock + # override a few lines ago. It'll be overwritten when the next + # timeserver attestation is verified. + # self.assertEqual( + # int(tuf.formats.datetime_to_unix_timestamp(iso8601.parse_date( + # '2016-11-02T21:06:05Z'))), tuf.conf.CLOCK_OVERRIDE) + + # 3. The currently trusted Root metadata in the Secondary's updater for the + # Director repository should list the same Timeserver keyid as the + # Secondary has noted is the currently trusted Timeserver key's keyid. + # This should be the 79c79... key we know was in the original root + # metadata. + initially_trusted_timeserver_keyid = \ + instance.timeserver_public_key['keyid'] + self.assertEqual( + initially_trusted_timeserver_keyid, + instance.updater.repositories['director'].metadata['current']['root'] + ['roles']['Timeserver']['keyids'][0]) + self.assertEqual( + '79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e', + initially_trusted_timeserver_keyid) + + + + # BUILD the ATTACK. + + # Simulate a request from the Secondary to the Timeserver containing the + # next nonce. (This populates instance.last_nonce_sent.) + instance.set_nonce_as_sent() + + # Construct a Timeserver Attestation that sets the clock to the future, + # near the end of the current UNIX epoch. Include the nonce this + # Secondary thinks it sent the Timeserver. + # (This has no signatures list yet.) + fastforward_bare = { + 'time': '2038-01-19T03:14:07Z', # a.k.a. 2147483647 in UNIX time + 'nonces': [instance.last_nonce_sent] + } + + uptane.formats.TIMESERVER_ATTESTATION_SCHEMA.check_match( + fastforward_bare) + + # Construct and check the signable version of the time attestation. + fastforward_signable = tuf.formats.make_signable(fastforward_bare) + uptane.formats.SIGNABLE_TIMESERVER_ATTESTATION_SCHEMA.check_match( + fastforward_signable) + + # Sign the fast-forward time attestation. + uptane.common.sign_signable( + fastforward_signable, + [self.key_timeserver_pri], + asn1_codec.DATATYPE_TIME_ATTESTATION, + metadata_format='json') + + + + # PERFORM the ATTACK. + + # Provide the Secondary with the fast-forward attestation. + # If the time_attestation is not deemed valid, an exception will be raised. + instance.update_time(fastforward_signable) + + + # Check results of the attack. + + # 1. There should be 3 trusted timeserver attestations (including the + # fast-forwarding attestation). + self.assertEqual(3, len(instance.all_valid_timeserver_times)) + + # 2. The current trusted time should be end-of-epoch from the + # fast-forwarding attestation. + self.assertEqual(2147483647, tuf.conf.CLOCK_OVERRIDE) # about epoch max + + + # CHECK ATTACK state: an update without the key rotated should now fail. + # (Fast-forward attack succeeds until Timeserver key is rotated.) + + archive_with_old_timeserver_key = os.path.join( + SAMPLES_DIR, 'metadata_samples_long_expiry', 'update_to_one_ecu', + 'full_metadata_archive.zip') + + + # TRY UPDATING during attack. This should fail with an + # ExpiredMetadataError, which will occur when we update the Root metadata + # but find it to be expired and so refuse to continue and update the other + # metadata. + with self.assertRaises(tuf.ExpiredMetadataError): + instance.process_metadata(archive_with_old_timeserver_key) + + # OLD, NOW WRONG: + # TRY UPDATING during attack. This should fail with a NoWorkingMirrorError + # # The individual errors for each mirror should be ExpiredMetadataErrors. + # # Check to make sure all the individual errors spooled in the + # # NoWorkingMirrorError are each an ExpiredMetadataError. + # try: + # instance.process_metadata(archive_with_old_timeserver_key) + # except tuf.NoWorkingMirrorError as e: + # for mirror in e.mirror_errors: + # self.assertIsInstance(e.mirror_errors[mirror], tuf.ExpiredMetadataError) + # else: + # self.Fail( + # 'Expected update to fail during attack and provide a ' + # 'NoWorkingMirrorError, which we would then check to confirm ' + # 'consists of one ExpiredMetadataError for each mirror.') + + + + # TODO: Consider generating more metadata to conduct more tests..... Ugh. + + + + # CHECK that the failed update had no strange side-effects by + # REPEATING all the initial-metadata-state and attacked-time-state checks + # above to make sure that the update that should have failed had no strange + # effects. + + # 1. There should be 3 trusted timeserver attestations (including the + # fast-forwarding attestation). + self.assertEqual(3, len(instance.all_valid_timeserver_times)) + + # 2. The current trusted time should be end-of-epoch from the + # fast-forwarding attestation. + self.assertEqual(2147483647, tuf.conf.CLOCK_OVERRIDE) # about epoch max + + # 3. The currently trusted Root metadata in the Secondary's updater for the + # Director repository should list the same Timeserver keyid as the + # Secondary has noted is the currently trusted Timeserver key's keyid. + # This should be the 79c79... key we know was in the original root + # metadata. + initially_trusted_timeserver_keyid = \ + instance.timeserver_public_key['keyid'] + self.assertEqual( + initially_trusted_timeserver_keyid, + instance.updater.repositories['director'].metadata['current']['root'] + ['roles']['Timeserver']['keyids'][0]) + self.assertEqual( + '79c796d7e87389d1ebad04edce49faef611d139ee41ea9fb1931732afbfaac2e', + initially_trusted_timeserver_keyid) + + + + # RESOLVE the ATTACK by providing the Secondary with metadata in which the + # timeserver key was rotated, which should allow the Secondary to update + # again. + # Provide a new root file with the timeserver key rotated. Update and + # confirm that the update succeeds. + archive_with_rotated_key = os.path.join( + SAMPLES_DIR, 'metadata_samples_long_expiry', 'timeserver_key_rotated', + 'full_metadata_archive.zip') + + # Update to the new metadata with the new Timeserver key. + # This will involve an initial failure due to an apparently-expired set of + # metadata, but then when the newly trusted Root metadata is inspected, it + # will be found to have contained an updated Timeserver key, which will + # lead to tuf.conf.CLOCK_OVERRIDE being reset to 0, resolving the attack. + # An update attempt will then be repeated and succeed. + instance.process_metadata(archive_with_rotated_key) + + now_trusted_timeserver_keyid = \ + instance.timeserver_public_key['keyid'] + + # CHECK RESULTING state: + + # 1. There should be zero trusted timeserver attestations immediately after + # rotation. + self.assertEqual(0, len(instance.all_valid_timeserver_attestations)) + + # 2. The trusted time and the TUF clock override should be 0, epoch start. + self.assertEqual( + ['1970-01-01T00:00:00Z'], instance.all_valid_timeserver_times) + self.assertEqual(0, tuf.conf.CLOCK_OVERRIDE) + + # 3. The currently trusted Root metadata in the Secondary's updater for the + # Director repository should list the same Timeserver keyid as the + # Secondary has noted is the currently trusted Timeserver key's keyid. + # This should be the da9c6... key we know is in the sample rotated + # metadata. + self.assertEqual( + now_trusted_timeserver_keyid, + instance.updater.repositories['director'].metadata['current']['root'] + ['roles']['Timeserver']['keyids'][0]) + self.assertEqual( + 'da9c65c96c5c4072f6984f7aa81216d776aca6664d49cb4dfafbc7119320d9cc', + now_trusted_timeserver_keyid) + + # For good measure, to avoid stupid mistakes in future test code changes. + # Make sure the key changed. + self.assertNotEqual( + initially_trusted_timeserver_keyid, now_trusted_timeserver_keyid) + + + # TODO: Try another update to provide an additional test that the attack + # has been fully resolved? + + + + + # Run unit tests. if __name__ == '__main__': unittest.main() diff --git a/uptane/clients/primary.py b/uptane/clients/primary.py index d502985..d8aefd2 100644 --- a/uptane/clients/primary.py +++ b/uptane/clients/primary.py @@ -340,9 +340,158 @@ def refresh_toplevel_metadata_from_repositories(self): See tuf.client.updater.Updater.refresh() for details, or the Uptane Implementation Specification, section 8.3.2 (Full Verification of Metadata). + + # TODO: This function is duplicated in primary.py and secondary.py. It must + # be moved to a general client.py as part of a fix to issue #14 + # (github.com/uptane/uptane/issues/14). + + This can raise TUF update exceptions like + - tuf.ExpiredMetadataError: + if after attempts to update the Root metadata succeeded or failed, + whatever currently trusted Root metadata we ended up with was expired. + - tuf.NoWorkingMirrorError: + if we could not obtain and verify all necessary metadata """ - self.updater.refresh() + # In order to provide Timeserver fast-forward attack protection, we do more + # than simply calling updater.refresh(). Instead, we: + # 1. Make note of the Timeserver key listed in the root metadata currently + # trusted by this client. + # 2. Attempt updater.refresh() + # 3. If refresh() failed (preferably only do this if it failed due to + # expired metadata), check to see if the Timeserver key listed in the + # root metadata NOW currently trusted is the same as before. If it is + # not, reset the clock and try to refresh() one more time. + # 4. Else if refresh() succeeded, check to see if the Timeserver key + # listed in the root metadata NOW currently trusted is the same as + # before. If it is not, reset the clock. Don't bother calling + # refresh() again, though. + + + # Make note of the currently-trusted Timeserver key(s) and threshold. + prior_timeserver_auth_info = self.updater.get_metadata( + self.director_repo_name, 'current')['root']['roles']['Timeserver'] + + # Refresh the Director first. If the Director refresh fails, we check to + # see if the Timeserver key has been rotated. + try: + self.updater.refresh(repo_name=self.director_repo_name) + + except (tuf.NoWorkingMirrorError, tuf.ExpiredMetadataError): + # TODO: <~> In the except line above, see if it's sufficient to only + # catch NoWorkingMirrorError here. (Do we ever get + # ExpiredMetadataError instead of NoWorkingMirrorError? + # Should we comb through the component errors in the + # NoWorkingMirrorErrors looking for ExpiredMetadataError? + # If so, write a function that returns True/False given the + # NoWorkingMirrorError, based on whether or not the failure was + # caused by ExpiredMetadataErrors. Consider generalizing to + # return an error class if the NoWorkingMirrorError is caused + # solely by one error class, and something else if the causes + # are various. + + new_timeserver_auth_info = self.updater.get_metadata( + self.director_repo_name, 'current')['root']['roles']['Timeserver'] + + if prior_timeserver_auth_info != new_timeserver_auth_info: + # TODO: Consider another, more invasive way to accomplish this (within + # root chain verification, after switch to theupdateframework/tuf) + # because there's a corner case here that isn't addressed: + # Suppose in root version X you change the Timeserver key after a + # fast-forward attack, then later in root version Y, change it + # back because you decide the key was not exposed or something.... + # If a client goes from root version X-1 to root version Y within + # this update cycle (it would root chain within the refresh + # call), then we won't notice here that the key ever changed, + # and we won't resolve the fast-forward attack. Detection should + # occur at a lower level, in every root chain link step. + # This will do for now, but fix the corner case by moving this + # check. + self.update_timeserver_key_and_reset_clock(prior_timeserver_auth_info) + # Since we failed to update and the Timeserver key changed, we try to + # refresh again, since we may have failed because of a fast-forward + # attack. + # Note that the only difference between this except clause and the + # try-except-else's else clause below is that we refresh again here. + self.updater.refresh() + + else: + raise + + else: + new_timeserver_auth_info = self.updater.get_metadata( + self.director_repo_name, 'current')['root']['roles']['Timeserver'] + + if prior_timeserver_auth_info != new_timeserver_auth_info: + self.update_timeserver_key_and_reset_clock(new_timeserver_auth_info) + + + # Now that we've dealt with the Director repository, deal with any and all + # other repositories, presumably Image Repositories. + for repository_name in self.updater.repositories: + if repository_name == self.director_repo_name: + continue + + self.updater.refresh(repo_name=repository_name) + + + + + + def update_timeserver_key_and_reset_clock(self, new_auth_info): + ''' + Update the expected timeserver key, reset the clock to epoch, and discard + old timeserver attestations. + This function assumes that the timeserver key has changed. (i.e. Do not + call it if the key has not changed.)) + + The argument new_auth_info is in the keyids+threshold format expected in + the Root metadata, e.g.: + {'keyids': ['1234...'], 'threshold': 1} + This implementation supports only one Timeserver key. + + # TODO: This function is duplicated in primary.py and secondary.py. It must + # be moved to a general client.py as part of a fix to issue #14 + # (github.com/uptane/uptane/issues/14). + ''' + + # TODO: Separate and migrate away from ROLE_SCHEMA. ROLE_SCHEMA is poorly + # named and used for too many distinct purposes. + tuf.formats.ROLE_SCHEMA.check_match(new_auth_info) + + if len(new_auth_info['keyids']) != 1 or new_auth_info['threshold'] != 1: + raise uptane.Error( + 'This implementation supports only a single key and threshold of ' + '1 for the Timeserver. The given authentication information drawn ' + 'from verified Root metadata does not match these constraints, ' + 'listing ' + str(len(new_auth_info['keyids'])) + ' keys and having ' + 'a threshold of ' + str(new_auth_info['threshold']) + '.') + + new_keyid = new_auth_info['keyids'][0] + + # We retrieve the key from tuf.keydb, using the keyid provided (obtained, + # by the caller of this function, from the 'roles' section of the currently + # trusted Director Root metadata. + # We could instead fetch the key information directly from the 'keys' + # section of the currently trusted Director Root metadata, looking it up + # using the keyid from the 'roles' section like this: + # self.updater.get_metadata(self.director_repo_name, 'current')['root']['keys'][new_trusted_timeserver_keyid] + # BUT we will instead use tuf.keydb.get_key(). keydb is fed the key + # information when the metadata is verified. The difference is only that + # certain implementations of general-purpose key rotation (TUF's TAP 8) + # might result in these not matching, and the more trustworthy source being + # tuf.keydb. (At the time of this writing, TAP 8 is not implemented here.) + # however, we do not fetch it directly, but request it from keydb, where + # that information ends up when the metadata is updated. There is a + # possible edge case if general-purpose key rotation is implemented.... + self.timeserver_public_key = tuf.keydb.get_key( + new_keyid, repository_name=self.director_repo_name) + + # Reset the clock to epoch and discard previously-trusted time attestations. + tuf.conf.CLOCK_OVERRIDE = 0 + self.all_valid_timeserver_times = [tuf.formats.unix_timestamp_to_datetime( + 0).isoformat() + 'Z'] + self.all_valid_timeserver_attestations = [] diff --git a/uptane/clients/secondary.py b/uptane/clients/secondary.py index c5accb0..1ff7072 100644 --- a/uptane/clients/secondary.py +++ b/uptane/clients/secondary.py @@ -30,6 +30,7 @@ import zipfile # to expand the metadata archive retrieved from the Primary import hashlib import iso8601 +import time import tuf.formats import tuf.keys @@ -470,6 +471,171 @@ def update_time(self, timeserver_attestation): + def refresh_toplevel_metadata_from_repositories(self): + """ + Refreshes client's metadata for the top-level roles: + root, targets, snapshot, and timestamp + + See tuf.client.updater.Updater.refresh() for details, or the + Uptane Implementation Specification, section 8.3.2 (Full Verification of + Metadata). + + # TODO: This function is duplicated in primary.py and secondary.py. It must + # be moved to a general client.py as part of a fix to issue #14 + # (github.com/uptane/uptane/issues/14). + + This can raise TUF update exceptions like + - tuf.ExpiredMetadataError: + if after attempts to update the Root metadata succeeded or failed, + whatever currently trusted Root metadata we ended up with was expired. + - tuf.NoWorkingMirrorError: + if we could not obtain and verify all necessary metadata + """ + + # In order to provide Timeserver fast-forward attack protection, we do more + # than simply calling updater.refresh(). Instead, we: + # 1. Make note of the Timeserver key listed in the root metadata currently + # trusted by this client. + # 2. Attempt updater.refresh() + # 3. If refresh() failed (preferably only do this if it failed due to + # expired metadata), check to see if the Timeserver key listed in the + # root metadata NOW currently trusted is the same as before. If it is + # not, reset the clock and try to refresh() one more time. + # 4. Else if refresh() succeeded, check to see if the Timeserver key + # listed in the root metadata NOW currently trusted is the same as + # before. If it is not, reset the clock. Don't bother calling + # refresh() again, though. + + + # Make note of the currently-trusted Timeserver key(s) and threshold. + prior_timeserver_auth_info = self.updater.get_metadata( + self.director_repo_name, 'current')['root']['roles']['Timeserver'] + + # Refresh the Director first. If the Director refresh fails, we check to + # see if the Timeserver key has been rotated. + try: + self.updater.refresh(repo_name=self.director_repo_name) + + except (tuf.NoWorkingMirrorError, tuf.ExpiredMetadataError): + # TODO: <~> In the except line above, see if it's sufficient to only + # catch NoWorkingMirrorError here. (Do we ever get + # ExpiredMetadataError instead of NoWorkingMirrorError? + # Should we comb through the component errors in the + # NoWorkingMirrorErrors looking for ExpiredMetadataError? + # If so, write a function that returns True/False given the + # NoWorkingMirrorError, based on whether or not the failure was + # caused by ExpiredMetadataErrors. Consider generalizing to + # return an error class if the NoWorkingMirrorError is caused + # solely by one error class, and something else if the causes + # are various. + + new_timeserver_auth_info = self.updater.get_metadata( + self.director_repo_name, 'current')['root']['roles']['Timeserver'] + + if prior_timeserver_auth_info != new_timeserver_auth_info: + # TODO: Consider another, more invasive way to accomplish this (within + # root chain verification, after switch to theupdateframework/tuf) + # because there's a corner case here that isn't addressed: + # Suppose in root version X you change the Timeserver key after a + # fast-forward attack, then later in root version Y, change it + # back because you decide the key was not exposed or something.... + # If a client goes from root version X-1 to root version Y within + # this update cycle (it would root chain within the refresh + # call), then we won't notice here that the key ever changed, + # and we won't resolve the fast-forward attack. Detection should + # occur at a lower level, in every root chain link step. + # This will do for now, but fix the corner case by moving this + # check. + self.update_timeserver_key_and_reset_clock(new_timeserver_auth_info) + # Since we failed to update and the Timeserver key changed, we try to + # refresh again, since we may have failed because of a fast-forward + # attack. + # Note that the only difference between this except clause and the + # try-except-else's else clause below is that we refresh again here. + self.updater.refresh() + + else: + raise + + else: + new_timeserver_auth_info = self.updater.get_metadata( + self.director_repo_name, 'current')['root']['roles']['Timeserver'] + + if prior_timeserver_auth_info != new_timeserver_auth_info: + self.update_timeserver_key_and_reset_clock(new_timeserver_auth_info) + + + # Now that we've dealt with the Director repository, deal with any and all + # other repositories, presumably Image Repositories. + for repository_name in self.updater.repositories: + if repository_name == self.director_repo_name: + continue + + self.updater.refresh(repo_name=repository_name) + + + + + + def update_timeserver_key_and_reset_clock(self, new_auth_info): + ''' + Update the expected timeserver key, reset the clock to epoch, and discard + old timeserver attestations. + This function assumes that the timeserver key has changed. (i.e. Do not + call it if the key has not changed.)) + + The argument new_auth_info is in the keyids+threshold format expected in + the Root metadata, e.g.: + {'keyids': ['1234...'], 'threshold': 1} + This implementation supports only one Timeserver key. + + # TODO: This function is duplicated in primary.py and secondary.py. It must + # be moved to a general client.py as part of a fix to issue #14 + # (github.com/uptane/uptane/issues/14). + ''' + + # TODO: Separate and migrate away from ROLE_SCHEMA. ROLE_SCHEMA is poorly + # named and used for too many distinct purposes. + tuf.formats.ROLE_SCHEMA.check_match(new_auth_info) + + if len(new_auth_info['keyids']) != 1 or new_auth_info['threshold'] != 1: + raise uptane.Error( + 'This implementation supports only a single key and threshold of ' + '1 for the Timeserver. The given authentication information drawn ' + 'from verified Root metadata does not match these constraints, ' + 'listing ' + str(len(new_auth_info['keyids'])) + ' keys and having ' + 'a threshold of ' + str(new_auth_info['threshold']) + '.') + + new_keyid = new_auth_info['keyids'][0] + + # We retrieve the key from tuf.keydb, using the keyid provided (obtained, + # by the caller of this function, from the 'roles' section of the currently + # trusted Director Root metadata. + # We could instead fetch the key information directly from the 'keys' + # section of the currently trusted Director Root metadata, looking it up + # using the keyid from the 'roles' section like this: + # self.updater.get_metadata(self.director_repo_name, 'current')['root']['keys'][new_trusted_timeserver_keyid] + # BUT we will instead use tuf.keydb.get_key(). keydb is fed the key + # information when the metadata is verified. The difference is only that + # certain implementations of general-purpose key rotation (TUF's TAP 8) + # might result in these not matching, and the more trustworthy source being + # tuf.keydb. (At the time of this writing, TAP 8 is not implemented here.) + # however, we do not fetch it directly, but request it from keydb, where + # that information ends up when the metadata is updated. There is a + # possible edge case if general-purpose key rotation is implemented.... + self.timeserver_public_key = tuf.keydb.get_key( + new_keyid, repository_name=self.director_repo_name) + + # Reset the clock to epoch and discard previously-trusted time attestations. + tuf.conf.CLOCK_OVERRIDE = 0 + self.all_valid_timeserver_times = [tuf.formats.unix_timestamp_to_datetime( + 0).isoformat() + 'Z'] + self.all_valid_timeserver_attestations = [] + + + + + def fully_validate_metadata(self): """ Treats the unvalidated metadata obtained from the Primary (which the @@ -504,7 +670,7 @@ def fully_validate_metadata(self): """ # Refresh the top-level metadata first (all repositories). - self.updater.refresh() + self.refresh_toplevel_metadata_from_repositories() validated_targets_for_this_ecu = []