diff --git a/demo/demo_primary.py b/demo/demo_primary.py index 7293856..5cabd00 100644 --- a/demo/demo_primary.py +++ b/demo/demo_primary.py @@ -494,7 +494,7 @@ def get_metadata_for_ecu(ecu_serial, force_partial_verification=False): fname = None if force_partial_verification: - fname = primary_ecu.get_partial_metadata_fname() + fname = primary_ecu.get_partial_metadata_archive_fname() else: # Note that in Python 2.7.4 and later, unzipping should prevent files from diff --git a/demo/demo_secondary.py b/demo/demo_secondary.py index e3f50b2..5c45b4e 100644 --- a/demo/demo_secondary.py +++ b/demo/demo_secondary.py @@ -63,6 +63,7 @@ _ecu_serial = 'TCUdemocar' _primary_host = demo.PRIMARY_SERVER_HOST _primary_port = demo.PRIMARY_SERVER_DEFAULT_PORT +_partial_verifying = False firmware_filename = 'secondary_firmware.txt' current_firmware_fileinfo = {} secondary_ecu = None @@ -79,7 +80,8 @@ def clean_slate( vin=_vin, ecu_serial=_ecu_serial, primary_host=None, - primary_port=None): + primary_port=None, + partial_verifying=_partial_verifying): """ """ @@ -88,12 +90,14 @@ def clean_slate( global _ecu_serial global _primary_host global _primary_port + global _partial_verifying global nonce global CLIENT_DIRECTORY global attacks_detected _vin = vin _ecu_serial = ecu_serial + _partial_verifying = partial_verifying if primary_host is not None: _primary_host = primary_host @@ -104,6 +108,12 @@ def clean_slate( CLIENT_DIRECTORY = os.path.join( uptane.WORKING_DIR, CLIENT_DIRECTORY_PREFIX + demo.get_random_string(5)) + # If secondary is partial verification then it would need director public key + if _partial_verifying: + key_director_pub = demo.import_public_key('director') + else: + key_director_pub = None + # Load the public timeserver key. key_timeserver_pub = demo.import_public_key('timeserver') @@ -154,7 +164,9 @@ def clean_slate( ecu_key=ecu_key, time=clock, firmware_fileinfo=factory_firmware_fileinfo, - timeserver_public_key=key_timeserver_pub) + timeserver_public_key=key_timeserver_pub, + director_public_key=key_director_pub, + partial_verifying=_partial_verifying) @@ -302,7 +314,8 @@ def update_cycle(): # Download the metadata from the Primary in the form of an archive. This # returns the binary data that we need to write to file. - metadata_archive = pserver.get_metadata(secondary_ecu.ecu_serial) + metadata_from_primary = pserver.get_metadata( + secondary_ecu.ecu_serial, secondary_ecu.partial_verifying) # Verify the time attestation and internalize the time (if verified, the time # will be used in place of system time to perform future metadata expiration @@ -326,7 +339,7 @@ def update_cycle(): secondary_ecu.full_client_dir, 'metadata_archive.zip') with open(archive_fname, 'wb') as fobj: - fobj.write(metadata_archive.data) + fobj.write(metadata_from_primary.data) # Now tell the Secondary reference implementation code where the archive file # is and let it expand and validate the metadata. 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 deleted file mode 100644 index d836c76..0000000 Binary files a/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.der and /dev/null differ 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..6773446 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..8c25a3b 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..ad86732 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": "1749f961bda975ef8db96b56b8b61465ef36fbbb45ce9c92248303851e36c21bd28d1cadfff9a12a0b1d87c3ea9294736d976a5a00b83167bc99c6b2a3a8860d" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "keys": { "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6": { "keyid_hash_algorithms": [ 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..e81cacc 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,3 @@ -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% + ;_k.c_f? l½j8i0g <=3_6T`GࡍY^SkVx +@~`)vzoB87obl"x/95pp( \ 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..b6040f0 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,16 +3,16 @@ { "keyid": "f93cfcf33d335ff43654ec6047e0a18dd5595ee3de53136b94c9c756788a0f97", "method": "ed25519", - "sig": "7606de7a3cb4d899755d8fe085f8834a356ca81b65814e89aa5062faa78360ff12b9977825fa9e14baf3daf63c4da2c354ec0fe233a98d3aac63d5758caab60e" + "sig": "dbf828452d952b1423b6797bceb6f1eea0f049cf3da73f42af85c032b3a4b3265d9eb164616ea94afe8bcf0d2c972a0abdf11a7a0a0107711bbf47eb9df7ff04" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "meta": { "root.json": { "hashes": { - "sha256": "2a6db46564a0fbc905bf7a36eddc172f1ce3a52871f18f2594e5160b2321e62d" + "sha256": "983203b28c67ea490db40bc82801aa771c9522ccbbc33bcf3239e37eef95523d" }, "length": 2120, "version": 1 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..1a9de0d 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..6b9c9a8 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": "df56f77ffad98db3152a9c27fda8220a60373174fb5b5173039bf5eb9d2a7fb23926f37d0b41f67c72a29ad20d3c908db327982c59852e986d270a3336432a03" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "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..f047f72 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..82d839b 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": "4d29caea1f135790c99f5112c89833c363e23a72f082dee707bf9723a9c45bda47f8bfd8711a646139e16d892c9a0ea99b86c85f021ce9db28ee70ae3d5c6e07" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "114817f21566942dbcdafe97e3d1aca1660db86d8920a872c65b76d9890409de" + "sha256": "9d98d3a1a89a277eb23fb3237709318fbea54249c539dbf5b53eb8318c75847a" }, "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..8375b5d 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 @@ -3,7 +3,7 @@ { "keyid": "94c836f0c45168f0a437eef0e487b910f58db4d462ae457b5730a4487130f290", "method": "ed25519", - "sig": "bdbbbfa6b75e98bbc5f04549f1b181e39cc7c8ad8bd86a41c061825e01ed5d2cf1a294cb45f7441cb15fe0302264a98c7813af699c12ba25ccee08878436c20b" + "sig": "f08d8dfe263e55facaaa16eda78a8e51fbbaa2e36ae47b93a8103ca0982dc3deb988f7a1aee5c805a322232b01299c5919b3f8cb6bf04cca7a68e9ac3903d309" } ], "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..b0f4698 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,16 +3,16 @@ { "keyid": "aaf05f8d054f8068bf6cb46beed7c824e2560802df462fc8681677586582ca99", "method": "ed25519", - "sig": "8cb2bff8f52a5aed8979a9c1ebfa047fb4ee58b63830037593bd240ceaafbae274c80c9d59aa3b6fba2bdd6de3c535e3230de2a51509042ca2f7d61523065709" + "sig": "5259eabac762bf61e0edce451f0645861ee79f3d6654d03c484badbff95e6c216daf82cc9a9a6285540a1126486fc5f3cf6a35985b7dc62ec32e4f2ab882d600" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "root.json": { "hashes": { - "sha256": "69385580f90dcd47d7d309070f65515188d392b41416d1efeb330978b77e4a96" + "sha256": "46f623b52e1e0d17bef556175227c90ea0d79c3f4e33957294fe5b1fdbddae76" }, "length": 2120, "version": 1 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..3d490d5 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": "0c2a95485dca56dadf4be8f8f015de79d92e015427c79a5ff134df63f6a81b19abd2bec2fd85840a7624c2409faaf694cbec2467d9012a42660e223000eb540d" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "d37a3f9b41bd7ad4c87bc978f0341cbeb081bdee0891f087f33d34963c565e16" + "sha256": "d637c37e4417c7649b275403eacf3bf2c0db913bc72ac2847e55968d07ea0716" }, "length": 594, "version": 1 diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive.zip b/samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive.zip new file mode 100644 index 0000000..0d6adf4 Binary files /dev/null and b/samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive.zip differ diff --git a/samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive/director/metadata/targets.der b/samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive/director/metadata/targets.der new file mode 100644 index 0000000..1a9de0d Binary files /dev/null and b/samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive/director/metadata/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/partial_metadata_archive/director/metadata/targets.json similarity index 59% rename from samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.json rename to samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive/director/metadata/targets.json index 8614ec3..6b9c9a8 100644 --- a/samples/metadata_samples_long_expiry/initial_w_no_update/director_targets.json +++ b/samples/metadata_samples_long_expiry/initial_w_no_update/partial_metadata_archive/director/metadata/targets.json @@ -3,7 +3,7 @@ { "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", "method": "ed25519", - "sig": "263a6d873455bac478366d92edc04cac55cc0e545b5f4249cf696254263d58de6a225446ce96725bccb83ffdaab548fcd89cb790020039ef336fb422364c1800" + "sig": "df56f77ffad98db3152a9c27fda8220a60373174fb5b5173039bf5eb9d2a7fb23926f37d0b41f67c72a29ad20d3c908db327982c59852e986d270a3336432a03" } ], "signed": { @@ -12,7 +12,7 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "targets": {}, "version": 1 } 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 deleted file mode 100644 index 09869c3..0000000 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.der and /dev/null differ 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..e44baac 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..8c25a3b 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..ad86732 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": "1749f961bda975ef8db96b56b8b61465ef36fbbb45ce9c92248303851e36c21bd28d1cadfff9a12a0b1d87c3ea9294736d976a5a00b83167bc99c6b2a3a8860d" } ], "signed": { @@ -12,7 +12,7 @@ "gz" ], "consistent_snapshot": false, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "keys": { "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6": { "keyid_hash_algorithms": [ 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..60a7e7d 100644 Binary files a/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.der and b/samples/metadata_samples_long_expiry/update_to_one_ecu/full_metadata_archive/director/metadata/snapshot.der differ 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..ce09e30 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,16 +3,16 @@ { "keyid": "f93cfcf33d335ff43654ec6047e0a18dd5595ee3de53136b94c9c756788a0f97", "method": "ed25519", - "sig": "701d882716b54c0953d6811e0d4e5cfe788d75f4d0c425af9b2ec9bd8e3abec3f2ac707575680601a1b983b11aa290ec7add7070734a6a05b2a1117a9a31320c" + "sig": "df224bc6165f35638d37cbd207d613660abf62abfa9c6d90b59f8989ad26e1f1661118863589ecaa29a3b36bff090c3dfec05106cb906c5ff7c08303ea66bc06" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "meta": { "root.json": { "hashes": { - "sha256": "2a6db46564a0fbc905bf7a36eddc172f1ce3a52871f18f2594e5160b2321e62d" + "sha256": "983203b28c67ea490db40bc82801aa771c9522ccbbc33bcf3239e37eef95523d" }, "length": 2120, "version": 1 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..ad83b24 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..763aac7 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": "f8ed79a8d122eb1eaf1132c980989480c36a4393ed1e6d63fcfa27623b996d395bc1db150692dd339a003a7338bdafacdae03204ebaeb9d64c10bb050715e003" } ], "signed": { @@ -12,8 +12,18 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "targets": { + "/BCU1.1.txt": { + "custom": { + "ecu_serial": "BCUdemocar" + }, + "hashes": { + "sha256": "1eb6fa5c6bb606c5326d6ef0ff05f5fcefde4e50c7daea530978090778b38bf4", + "sha512": "9727058c2ba828fdd2fc5ae02f52c10e47404283f92df3539989e2ada3cf7e85a9772faed1bd0bad3fc2bd8f6e5d15b976b8e832dd46874be72b994bc57a62a0" + }, + "length": 18 + }, "/TCU1.1.txt": { "custom": { "ecu_serial": "TCUdemocar" 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..7277911 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..53a183c 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": "19ecc7d5ae73238e91bc15577837d678d845f3a9efb0f23f908d600f6aa870198a391494f2440b15c9b460eed6ded0e30eaf4ffa8b8ae0eb52da594deb46b008" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "d6a27db7727136afedc07d1e34bb078a6436c6779fa13d324942f135e04d0710" + "sha256": "36020d21bbdaa8581156a333541367100c2409c48f35e018888c4fd5c9b1f9d7" }, "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..8375b5d 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 @@ -3,7 +3,7 @@ { "keyid": "94c836f0c45168f0a437eef0e487b910f58db4d462ae457b5730a4487130f290", "method": "ed25519", - "sig": "bdbbbfa6b75e98bbc5f04549f1b181e39cc7c8ad8bd86a41c061825e01ed5d2cf1a294cb45f7441cb15fe0302264a98c7813af699c12ba25ccee08878436c20b" + "sig": "f08d8dfe263e55facaaa16eda78a8e51fbbaa2e36ae47b93a8103ca0982dc3deb988f7a1aee5c805a322232b01299c5919b3f8cb6bf04cca7a68e9ac3903d309" } ], "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..b0f4698 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,16 +3,16 @@ { "keyid": "aaf05f8d054f8068bf6cb46beed7c824e2560802df462fc8681677586582ca99", "method": "ed25519", - "sig": "8cb2bff8f52a5aed8979a9c1ebfa047fb4ee58b63830037593bd240ceaafbae274c80c9d59aa3b6fba2bdd6de3c535e3230de2a51509042ca2f7d61523065709" + "sig": "5259eabac762bf61e0edce451f0645861ee79f3d6654d03c484badbff95e6c216daf82cc9a9a6285540a1126486fc5f3cf6a35985b7dc62ec32e4f2ab882d600" } ], "signed": { "_type": "Snapshot", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "root.json": { "hashes": { - "sha256": "69385580f90dcd47d7d309070f65515188d392b41416d1efeb330978b77e4a96" + "sha256": "46f623b52e1e0d17bef556175227c90ea0d79c3f4e33957294fe5b1fdbddae76" }, "length": 2120, "version": 1 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..3d490d5 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": "0c2a95485dca56dadf4be8f8f015de79d92e015427c79a5ff134df63f6a81b19abd2bec2fd85840a7624c2409faaf694cbec2467d9012a42660e223000eb540d" } ], "signed": { "_type": "Timestamp", - "expires": "2037-09-28T12:46:18Z", + "expires": "2038-01-18T03:14:07Z", "meta": { "snapshot.json": { "hashes": { - "sha256": "d37a3f9b41bd7ad4c87bc978f0341cbeb081bdee0891f087f33d34963c565e16" + "sha256": "d637c37e4417c7649b275403eacf3bf2c0db913bc72ac2847e55968d07ea0716" }, "length": 594, "version": 1 diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive.zip b/samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive.zip new file mode 100644 index 0000000..ee277c0 Binary files /dev/null and b/samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive.zip differ diff --git a/samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive/director/metadata/targets.der b/samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive/director/metadata/targets.der new file mode 100644 index 0000000..ad83b24 Binary files /dev/null and b/samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive/director/metadata/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/partial_metadata_archive/director/metadata/targets.json similarity index 53% rename from samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.json rename to samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive/director/metadata/targets.json index f883915..763aac7 100644 --- a/samples/metadata_samples_long_expiry/update_to_one_ecu/director_targets.json +++ b/samples/metadata_samples_long_expiry/update_to_one_ecu/partial_metadata_archive/director/metadata/targets.json @@ -3,7 +3,7 @@ { "keyid": "630cf584f392430b2119a4395e39624e86f5e5c5374507a789be5cf35bf090d6", "method": "ed25519", - "sig": "e97a2e9d819555cc2c8af799cb2020857a0217ca5246d3365e3d881d9f53aa94ded9ef6c64caa8b606728b52451555c3a79500c266163b9a66933bde7012c302" + "sig": "f8ed79a8d122eb1eaf1132c980989480c36a4393ed1e6d63fcfa27623b996d395bc1db150692dd339a003a7338bdafacdae03204ebaeb9d64c10bb050715e003" } ], "signed": { @@ -12,8 +12,18 @@ "keys": {}, "roles": [] }, - "expires": "2037-09-28T12:46:29Z", + "expires": "2038-01-18T03:14:15Z", "targets": { + "/BCU1.1.txt": { + "custom": { + "ecu_serial": "BCUdemocar" + }, + "hashes": { + "sha256": "1eb6fa5c6bb606c5326d6ef0ff05f5fcefde4e50c7daea530978090778b38bf4", + "sha512": "9727058c2ba828fdd2fc5ae02f52c10e47404283f92df3539989e2ada3cf7e85a9772faed1bd0bad3fc2bd8f6e5d15b976b8e832dd46874be72b994bc57a62a0" + }, + "length": 18 + }, "/TCU1.1.txt": { "custom": { "ecu_serial": "TCUdemocar" diff --git a/tests/test_primary.py b/tests/test_primary.py index f7087a9..a9db3fc 100644 --- a/tests/test_primary.py +++ b/tests/test_primary.py @@ -873,11 +873,11 @@ def test_61_get_full_metadata_archive_fname(self): - def test_62_get_partial_metadata_fname(self): + def test_62_get_partial_metadata_archive_fname(self): # TODO: More thorough tests. - fname = TestPrimary.instance.get_partial_metadata_fname() + fname = TestPrimary.instance.get_partial_metadata_archive_fname() self.assertTrue(fname) diff --git a/tests/test_secondary.py b/tests/test_secondary.py index cdd92bd..509aa94 100644 --- a/tests/test_secondary.py +++ b/tests/test_secondary.py @@ -52,23 +52,60 @@ TEST_DATA_DIR = os.path.join(uptane.WORKING_DIR, 'tests', 'test_data') TEST_PINNING_FNAME = os.path.join(TEST_DATA_DIR, 'pinned.json') -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')] -# 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] +# For each Secondary instance we'll use in testing, a dictionary of the +# client directory, whether or not the instance is partial-verifying, the +# vehicle's ID, the Secondary's ID, and a reference to the instance. +# Also note the nonce we'll use when validating sample time attestation data. +# Changing the nonce, vin and ecu_serial would require producing new signed +# test data from the Timeserver (in the case of nonce) or a Secondary (in the +# case of the others). -# 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'] + +TEST_INSTANCES = { + 'temp_secondary0': { + 'client_dir': os.path.join(TEST_DATA_DIR, 'temp_secondary0'), + 'partial_verifying': False, + 'vin': 'democar', + 'ecu_serial': 'TCUdemocar', + 'instance': None}, + 'temp_secondary1': { + 'client_dir': os.path.join(TEST_DATA_DIR, 'temp_secondary1'), + 'partial_verifying': False, + 'vin': 'democar', + 'ecu_serial': '00000', + 'instance': None}, + 'temp_secondary2': { + 'client_dir': os.path.join(TEST_DATA_DIR, 'temp_secondary2'), + 'partial_verifying': False, + 'vin': '000', + 'ecu_serial': '00000', + 'instance': None}, + 'temp_partial_secondary0': { + 'client_dir': os.path.join(TEST_DATA_DIR, 'temp_partial_secondary0'), + 'partial_verifying': True, + 'vin': 'democar', + 'ecu_serial': 'BCUdemocar', + 'instance': None}, + 'temp_partial_secondary1': { + 'client_dir': os.path.join(TEST_DATA_DIR, 'temp_partial_secondary1'), + 'partial_verifying': True, + 'vin': 'democar', + 'ecu_serial': 'pv_00000', + 'instance': None}, + 'temp_partial_secondary2': { + 'client_dir': os.path.join(TEST_DATA_DIR, 'temp_partial_secondary2'), + 'partial_verifying': True, + 'vin': '000', + 'ecu_serial': 'pv_00000', + 'instance': None} +} # Set starting firmware fileinfo (that this ECU had coming from the factory) # It will serve as the initial firmware state for the Secondary clients. +# Here abbreviations pv and fv stands for partial verification and full +# verification correspondingly. factory_firmware_fileinfo = { 'filepath': '/secondary_firmware.txt', 'fileinfo': { @@ -77,7 +114,7 @@ 'sha256': '6b9f987226610bfed08b824c93bf8b2f59521fce9a2adef80c495f363c1c9c44'}, 'length': 37}} -expected_updated_fileinfo = { +fv_expected_updated_fileinfo = { 'filepath': '/TCU1.1.txt', 'fileinfo': { 'custom': {'ecu_serial': 'TCUdemocar'}, @@ -86,12 +123,22 @@ 'sha256': '56d7cd56a85e34e40d005e1f79c0e95d6937d5528ac0b301dbe68d57e03a5c21'}, 'length': 17}} +pv_expected_updated_fileinfo = { + 'filepath': "/BCU1.1.txt", + 'fileinfo': { + "custom": {"ecu_serial": "BCUdemocar"}, + "hashes": { + "sha256": "1eb6fa5c6bb606c5326d6ef0ff05f5fcefde4e50c7daea530978090778b38bf4", + "sha512": "9727058c2ba828fdd2fc5ae02f52c10e47404283f92df3539989e2ada3cf7e85a9772faed1bd0bad3fc2bd8f6e5d15b976b8e832dd46874be72b994bc57a62a0"}, + "length": 18}} + def destroy_temp_dir(): # Clean up anything that may currently exist in the temp test directories. - for client_dir in TEMP_CLIENT_DIRS: - if os.path.exists(client_dir): - shutil.rmtree(client_dir) + for secondary_ecu in TEST_INSTANCES: + instance_data = TEST_INSTANCES[secondary_ecu] + if os.path.exists(instance_data['client_dir']): + shutil.rmtree(instance_data['client_dir']) @@ -152,9 +199,10 @@ def setUpClass(cls): # We're going to cheat in this test module for the purpose of testing # and update tuf.conf.repository_directories before each Secondary is # created, to refer to the client we're creating. - for client_dir in TEMP_CLIENT_DIRS: + for secondary_ecu in TEST_INSTANCES: + instance_data = TEST_INSTANCES[secondary_ecu] uptane.common.create_directory_structure_for_client( - client_dir, + instance_data['client_dir'], TEST_PINNING_FNAME, {'imagerepo': TEST_IMAGE_REPO_ROOT_FNAME, 'director': TEST_DIRECTOR_ROOT_FNAME}) @@ -191,8 +239,8 @@ def test_01_init(self): secondary.Secondary( full_client_dir=42, director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin= TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -208,10 +256,10 @@ def test_01_init(self): # Invalid director_repo_name with self.assertRaises(tuf.FormatError): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=42, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -222,10 +270,10 @@ def test_01_init(self): # Unknown director_repo_name with self.assertRaises(uptane.Error): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name='string_that_is_not_a_known_repo_name', - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -236,10 +284,10 @@ def test_01_init(self): # Invalid VIN: with self.assertRaises(tuf.FormatError): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, vin=5, - ecu_serial=ecu_serials[0], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -250,9 +298,9 @@ def test_01_init(self): # Invalid ECU Serial with self.assertRaises(tuf.FormatError): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], ecu_serial=500, ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, @@ -264,10 +312,10 @@ def test_01_init(self): # Invalid ECU Key with self.assertRaises(tuf.FormatError): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key={''}, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -278,10 +326,10 @@ def test_01_init(self): # Invalid initial time: with self.assertRaises(tuf.FormatError): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time='potato', timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -292,10 +340,10 @@ def test_01_init(self): # Invalid director_public_key: with self.assertRaises(tuf.FormatError): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -310,10 +358,10 @@ def test_01_init(self): # for full verification are determined based on the root metadata file. with self.assertRaises(uptane.Error): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -322,10 +370,10 @@ def test_01_init(self): partial_verifying=False) with self.assertRaises(uptane.Error): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, @@ -337,10 +385,10 @@ def test_01_init(self): # Invalid timeserver key with self.assertRaises(tuf.FormatError): secondary.Secondary( - full_client_dir=TEMP_CLIENT_DIRS[0], + full_client_dir=TEST_INSTANCES['temp_secondary0']['client_dir'], director_repo_name=demo.DIRECTOR_REPO_NAME, - vin=vins[0], - ecu_serial=ecu_serials[0], + vin=TEST_INSTANCES['temp_secondary0']['vin'], + ecu_serial=TEST_INSTANCES['temp_secondary0']['ecu_serial'], ecu_key=TestSecondary.secondary_ecu_key, time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.initial_time, # INVALID @@ -362,16 +410,24 @@ def test_01_init(self): # Initialize three 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] + for secondary_ecu in TEST_INSTANCES: + instance_data = TEST_INSTANCES[secondary_ecu] + client_dir = instance_data['client_dir'] + ecu_serial = instance_data['ecu_serial'] + vin = instance_data['vin'] + + # Partial verification Secondaries need to be initialized with the + # Director's public key. + if instance_data['partial_verifying']: + director_public_key_for_ecu = self.key_directortargets_pub + else: + director_public_key_for_ecu = None # Try initializing each of three 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. + # work. Save the instances for future tests as elements in a module + # variable (TEST_INSTANCES) to save time and code. tuf.conf.repository_directory = client_dir - secondary_instances[i] = secondary.Secondary( + instance_data['instance'] = secondary.Secondary( full_client_dir=client_dir, director_repo_name=demo.DIRECTOR_REPO_NAME, vin=vin, @@ -380,11 +436,9 @@ def test_01_init(self): time=TestSecondary.initial_time, timeserver_public_key=TestSecondary.key_timeserver_pub, firmware_fileinfo=factory_firmware_fileinfo, - director_public_key=None, - partial_verifying=False) - - instance = secondary_instances[i] - + director_public_key=director_public_key_for_ecu, + partial_verifying=instance_data['partial_verifying']) + instance = instance_data['instance'] # Check the fields initialized in the instance to make sure they're correct. # Fields initialized from parameters @@ -399,11 +453,9 @@ def test_01_init(self): TestSecondary.initial_time, instance.all_valid_timeserver_times[1]) self.assertEqual( TestSecondary.key_timeserver_pub, instance.timeserver_public_key) - self.assertTrue(None is instance.director_public_key) - self.assertFalse(instance.partial_verifying) # Fields initialized, but not directly with parameters - self.assertTrue(None is instance.last_nonce_sent) + self.assertIsNone(instance.last_nonce_sent) self.assertTrue(instance.nonce_next) # Random value self.assertIsInstance( instance.updater, tuf.client.updater.Updater) @@ -448,7 +500,7 @@ def test_10_nonce_rotation(self): """ # We'll just test one of the three client instances, since it shouldn't # make a difference. - instance = secondary_instances[0] + instance = TEST_INSTANCES['temp_secondary0']['instance'] old_nonce = instance.nonce_next @@ -471,7 +523,7 @@ def test_20_update_time(self): # We'll just test one of the three client instances, since it shouldn't # make a difference. - instance = secondary_instances[0] + instance = TEST_INSTANCES['temp_secondary0']['instance'] # Try a good time attestation first, signed by an expected timeserver key, # with an expected nonce (previously "received" from a Secondary) @@ -574,7 +626,8 @@ def test_25_generate_signed_ecu_manifest(self): # We'll just test one of the three client instances, since it shouldn't # make a difference. - ecu_manifest = secondary_instances[0].generate_signed_ecu_manifest() + ecu_manifest = TEST_INSTANCES[ + 'temp_secondary0']['instance'].generate_signed_ecu_manifest() # If the ECU Manifest is in DER format, check its format and then # convert back to JSON so that we can inspect it further. @@ -612,9 +665,12 @@ def test_40_process_metadata(self): Tests uptane.clients.secondary.Secondary::process_metadata() Tests three 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 + - TEST_INSTANCES['temp_secondary0'] + an update is provided in Director metadata + - TEST_INSTANCES['temp_secondary1'] + no update is provided in Director metadata + - TEST_INSTANCES['temp_secondary2'] + no Director metadata can be retrieved """ # --- Test this test module's setup (defensive) @@ -623,48 +679,66 @@ def test_40_process_metadata(self): # client directories when the directories were created by the # create_directory_structure_for_client() calls in setUpClass above, and # only the root metadata file. - for client_dir in TEMP_CLIENT_DIRS: - for repo in ['director', 'imagerepo']: + for secondary_ecu in TEST_INSTANCES: + instance_data = TEST_INSTANCES[secondary_ecu] + if instance_data['partial_verifying']: + repo_list = ['director'] + else: + repo_list = ['director', 'imagerepo'] + for repo in repo_list: self.assertEqual( ['root.' + tuf.conf.METADATA_FORMAT], sorted(os.listdir(os.path.join( - client_dir, 'metadata', repo, 'current')))) + instance_data['client_dir'], 'metadata', repo, 'current')))) # --- Set up this test # Location of the sample Primary-produced metadata archive - sample_archive_fname = os.path.join( + sample_fv_archive_fname = os.path.join( uptane.WORKING_DIR, 'samples', 'metadata_samples_long_expiry', 'update_to_one_ecu', 'full_metadata_archive.zip') + sample_pv_archive_fname = os.path.join( + uptane.WORKING_DIR, 'samples', 'metadata_samples_long_expiry', + 'update_to_one_ecu', 'partial_metadata_archive.zip') + - assert os.path.exists(sample_archive_fname), 'Cannot test ' \ + assert os.path.exists(sample_fv_archive_fname), 'Cannot test ' \ 'process_metadata; unable to find expected sample metadata archive' + \ - ' at ' + repr(sample_archive_fname) + ' at ' + repr(sample_fv_archive_fname) + assert os.path.exists(sample_pv_archive_fname), 'Cannot test ' \ + 'process_metadata; unable to find expected sample metadata archive' + \ + ' at ' + repr(sample_pv_archive_fname) # Continue set-up followed by the test, per client. - for i in range(0, len(TEMP_CLIENT_DIRS)): - client_dir = TEMP_CLIENT_DIRS[i] - instance = secondary_instances[i] + # Only tests the full verification secondaries + for secondary_ecu in TEST_INSTANCES: + instance_data = TEST_INSTANCES[secondary_ecu] + client_dir = instance_data['client_dir'] + instance = instance_data['instance'] # Make sure TUF uses the right client directory. # Hack to allow multiple clients to run in the same Python process. # See comments in SetUpClass() method. tuf.conf.repository_directory = client_dir - # Location in the client directory to which we'll copy the archive. - archive_fname = os.path.join(client_dir, 'full_metadata_archive.zip') - - # Copy the sample archive into place in the client directory. - shutil.copy(sample_archive_fname, archive_fname) + # Getting the location in the client directory to which we'll copy the archive + # and then copy the sample archive into place in the client directory. + if instance_data['partial_verifying']: + archive_fname = os.path.join(client_dir, 'partial_metadata_archive.zip') + shutil.copy(sample_pv_archive_fname, archive_fname) + else: + archive_fname = os.path.join(client_dir, 'full_metadata_archive.zip') + shutil.copy(sample_fv_archive_fname, archive_fname) # --- Perform the test - # Process this sample metadata. + # Process this sample metadata - if instance is secondary_instances[2]: - # Expect the update to fail for the third Secondary client. + if instance_data in [TEST_INSTANCES['temp_secondary2'], + TEST_INSTANCES['temp_partial_secondary2']]: + # Expect the update to fail for the third and fifth Secondary client. with self.assertRaises(tuf.NoWorkingMirrorError): instance.process_metadata(archive_fname) continue @@ -673,8 +747,14 @@ def test_40_process_metadata(self): instance.process_metadata(archive_fname) # Make sure the archive of unverified metadata was expanded - for repo in ['director', 'imagerepo']: - for role in ['root', 'snapshot', 'targets', 'timestamp']: + if instance_data['partial_verifying']: + repo_list = ['director'] + roles_list = ['targets'] + else: + repo_list = ['director', 'imagerepo'] + roles_list = ['root', 'snapshot', 'targets', 'timestamp'] + for repo in repo_list: + for role in roles_list: self.assertTrue(os.path.exists(client_dir + '/unverified/' + repo + '/metadata/' + role + '.' + tuf.conf.METADATA_FORMAT)) @@ -685,41 +765,73 @@ def test_40_process_metadata(self): # For clients 0 and 1, we expect root, snapshot, targets, and timestamp for # both director and image repo. - for client_dir in [TEMP_CLIENT_DIRS[0], TEMP_CLIENT_DIRS[1]]: - for repo in ['director', 'imagerepo']: - self.assertEqual([ - 'root.' + tuf.conf.METADATA_FORMAT, - 'snapshot.' + tuf.conf.METADATA_FORMAT, - 'targets.' + tuf.conf.METADATA_FORMAT, - 'timestamp.' + tuf.conf.METADATA_FORMAT], - sorted(os.listdir(os.path.join(client_dir, 'metadata', repo, - 'current')))) - - # For client 2, we are certain that Director metadata will have failed to - # update. Image Repository metadata may or may not have updated before the + # For clients 3 and 4, we expect root and targets for director repo + instances = [TEST_INSTANCES['temp_secondary0'], + TEST_INSTANCES['temp_secondary1'], + TEST_INSTANCES['temp_partial_secondary0'], + TEST_INSTANCES['temp_partial_secondary1']] + + for instance_data in instance: + if instance_data['partial_verifying']: + repo_list = ['director'] + # Both root and targets metadata would be present as there would a root + # file present when the ECU is manufactured, which would be used to + # establish a root of trust when the ECU is used for the first time. + roles_list = ['root','targets'] + else: + repo_list = ['director', 'imagerepo'] + roles_list = ['root', 'snapshot', 'targets', 'timestamp'] + roles_in_repo_directory = [] + + for role in roles_list: + roles_in_repo_directory.append( + role + '.' + tuf.conf.METADATA_FORMAT) + + for repo in repo_list: + self.assertEqual(roles_in_repo_directory, + sorted(os.listdir(os.path.join(instance_data['client_dir'], + 'metadata', repo, 'current')))) + + # For client 2 and 5, we are certain that Director metadata will have failed + # to update. Image Repository metadata may or may not have updated before the # Director repository update failure, so we don't check that. Client 2 # started with root metadata for the Director repository, so that is all # we expect to find. - self.assertEqual( - ['root.' + tuf.conf.METADATA_FORMAT], - sorted(os.listdir(os.path.join(TEMP_CLIENT_DIRS[2], 'metadata', - 'director', 'current')))) + for instance_data in [TEST_INSTANCES['temp_secondary2'], + TEST_INSTANCES['temp_partial_secondary2']]: + self.assertEqual( + ['root.' + tuf.conf.METADATA_FORMAT], + sorted(os.listdir(os.path.join(instance_data['client_dir'], + 'metadata', 'director', 'current')))) # Second: Check targets each Secondary client has been instructed to # install (and has in turn validated). - # Client 0 should have validated expected_updated_fileinfo. + # Client 0 should have validated fv_expected_updated_fileinfo. + self.assertEqual( + fv_expected_updated_fileinfo, + TEST_INSTANCES[ + 'temp_secondary0']['instance'].validated_targets_for_this_ecu[0]) + + # Client 3 should have validated pv_expected_updated_fileinfo. self.assertEqual( - expected_updated_fileinfo, - secondary_instances[0].validated_targets_for_this_ecu[0]) + pv_expected_updated_fileinfo, + TEST_INSTANCES[ + 'temp_partial_secondary0']['instance'].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) - self.assertFalse(secondary_instances[2].validated_targets_for_this_ecu) + # Clients 1, 2, 4 and should have no validated targets. + self.assertFalse(TEST_INSTANCES[ + 'temp_secondary1']['instance'].validated_targets_for_this_ecu) + self.assertFalse(TEST_INSTANCES[ + 'temp_secondary2']['instance'].validated_targets_for_this_ecu) + self.assertFalse(TEST_INSTANCES[ + 'temp_partial_secondary1']['instance'].validated_targets_for_this_ecu) + self.assertFalse(TEST_INSTANCES[ + 'temp_partial_secondary2']['instance'].validated_targets_for_this_ecu) # Finally, test behavior if the file we indicate does not exist. - instance = secondary_instances[0] + instance = TEST_INSTANCES['temp_secondary0']['instance'] with self.assertRaises(uptane.Error): instance.process_metadata('some_file_that_does_not_actually_exist.xyz') @@ -729,24 +841,61 @@ def test_40_process_metadata(self): def test_50_validate_image(self): - image_fname = 'TCU1.1.txt' + # In these tests, Secondary ECU were or were not given instructions to + # install a new update + # If instructed + # full verification Secondary will install 'TCU1.1.txt' + # partial verification Secondary will install 'BCU1.1.txt' + fv_image_fname = 'TCU1.1.txt' + pv_image_fname = 'BCU1.1.txt' + sample_image_location = os.path.join(demo.DEMO_DIR, 'images') - client_unverified_targets_dir = TEMP_CLIENT_DIRS[0] + '/unverified_targets' - if os.path.exists(client_unverified_targets_dir): - shutil.rmtree(client_unverified_targets_dir) - os.mkdir(client_unverified_targets_dir) + # Copy the firmware into the Secondary's unverified targets directory. + # (This is what the Secondary would do when receiving the file from + # the Primary.) + # Delete and recreate the unverified targets directory first. + for secondary_ecu in TEST_INSTANCES: + instance_data = TEST_INSTANCES[secondary_ecu] + client_unverified_targets_dir = os.path.join( + instance_data['client_dir'], 'unverified_targets') + + if os.path.exists(client_unverified_targets_dir): + shutil.rmtree(client_unverified_targets_dir) + os.mkdir(client_unverified_targets_dir) + + if instance_data['partial_verifying']: + image_fname = pv_image_fname + else: + image_fname = fv_image_fname + + shutil.copy( + os.path.join(sample_image_location, image_fname), + client_unverified_targets_dir) + + # Validate the appropriate update image for each secondary - shutil.copy( - os.path.join(sample_image_location, image_fname), - client_unverified_targets_dir) + # Secondaries 0-2 are running full verification + TEST_INSTANCES[ + 'temp_secondary0']['instance'].validate_image(fv_image_fname) + + with self.assertRaises(uptane.Error): + TEST_INSTANCES[ + 'temp_secondary1']['instance'].validate_image(fv_image_fname) + with self.assertRaises(uptane.Error): + TEST_INSTANCES[ + 'temp_secondary2']['instance'].validate_image(fv_image_fname) - secondary_instances[0].validate_image(image_fname) + #Secondaries 3-5 are running partial verification + TEST_INSTANCES[ + 'temp_partial_secondary0']['instance'].validate_image(pv_image_fname) with self.assertRaises(uptane.Error): - secondary_instances[1].validate_image(image_fname) + TEST_INSTANCES[ + 'temp_partial_secondary1']['instance'].validate_image(pv_image_fname) with self.assertRaises(uptane.Error): - secondary_instances[2].validate_image(image_fname) + TEST_INSTANCES[ + 'temp_partial_secondary2']['instance'].validate_image(pv_image_fname) diff --git a/uptane/clients/primary.py b/uptane/clients/primary.py index f26c271..db9be46 100644 --- a/uptane/clients/primary.py +++ b/uptane/clients/primary.py @@ -159,7 +159,7 @@ class Primary(object): # Consider inheriting from Secondary and refactoring. moved into place (renamed) after it has been fully written, to avoid race conditions. - self.distributable_partial_metadata_fname: + self.distributable_partial_metadata_archive_fname: The filename at which the Director's targets metadata file is stored after each update cycle, once it is safe to use. This is atomically moved into place (renamed) after it has been fully written, to avoid race conditions. @@ -187,7 +187,7 @@ class Primary(object): # Consider inheriting from Secondary and refactoring. update_exists_for_ecu(ecu_serial) get_image_fname_for_ecu(ecu_serial) get_full_metadata_archive_fname() - get_partial_metadata_fname() + get_partial_metadata_archive_fname() register_new_secondary(ecu_serial) Private methods: @@ -301,12 +301,10 @@ def __init__( full_client_dir, 'metadata', 'full_metadata_archive.zip') # TODO: Some of these assumptions are unseemly. Reconsider. - self.temp_partial_metadata_fname = os.path.join( - full_client_dir, 'metadata', 'temp_director_targets.' + - tuf.conf.METADATA_FORMAT) - self.distributable_partial_metadata_fname = os.path.join( - full_client_dir, 'metadata', 'director_targets.' + - tuf.conf.METADATA_FORMAT) + self.temp_partial_metadata_archive_fname = os.path.join( + full_client_dir, 'metadata', 'temp_partial_metadata_archive.zip') + self.distributable_partial_metadata_archive_fname = os.path.join( + full_client_dir, 'metadata', 'partial_metadata_archive.zip') # Initializations not directly related to arguments. self.nonces_to_send = [] @@ -770,7 +768,7 @@ def get_full_metadata_archive_fname(self): - def get_partial_metadata_fname(self): + def get_partial_metadata_archive_fname(self): """ Returns the absolute-path filename of the Director's targets.json metadata file, necessary for performing partial validation of target files (as a @@ -781,7 +779,7 @@ def get_partial_metadata_fname(self): file is completely written. If this Primary has never completed an update cycle, it will not exist yet. """ - return self.distributable_partial_metadata_fname + return self.distributable_partial_metadata_archive_fname @@ -1207,7 +1205,7 @@ def save_distributable_metadata_files(self): a zip archive of all the metadata files, from all repositories, validated by this Primary, for use by Full Verification Secondaries. - - self.distributable_partial_metadata_fname + - self.distributable_partial_metadata_archive_fname the Director Targets role file alone, for use by Partial Verification Secondaries @@ -1267,23 +1265,33 @@ def save_distributable_metadata_files(self): # Copy the Director's targets file to a temp location for partial-verifying # Secondaries. - director_targets_file = os.path.join( - self.full_client_dir, - 'metadata', - self.director_repo_name, - 'current', - 'targets.' + tuf.conf.METADATA_FORMAT) - if os.path.exists(self.temp_partial_metadata_fname): - os.remove(self.temp_partial_metadata_fname) - shutil.copyfile(director_targets_file, self.temp_partial_metadata_fname) + with zipfile.ZipFile(self.temp_partial_metadata_archive_fname, 'w') \ + as archive: + + # Need 'target' metadata from only director repo + repo_name = self.director_repo_name + # Construct path to "current" metadata directory for that repository in + # the client metadata directory, relative to Uptane working directory. + abs_repo_dir = os.path.join(metadata_base_dir, repo_name, 'current') + + # Archive only 'targets' metadat file for partial verification + role_fname = 'targets.' + tuf.conf.METADATA_FORMAT + # Reconstruct file path relative to Uptane working directory. + role_abs_fname = os.path.join(abs_repo_dir, role_fname) + + # Write the file to the archive, adjusting the path in the archive so + # that when expanded, it resembles repository structure rather than + # a client directory structure. + archive.write(role_abs_fname, + os.path.join(repo_dir, 'metadata', role_fname)) # Now move both Full and Partial metadata files into place. For each file, # this happens atomically on POSIX-compliant systems and replaces any # existing file. os.rename( - self.temp_partial_metadata_fname, - self.distributable_partial_metadata_fname) + self.temp_partial_metadata_archive_fname, + self.distributable_partial_metadata_archive_fname) os.rename( self.temp_full_metadata_archive_fname, self.distributable_full_metadata_archive_fname) diff --git a/uptane/clients/secondary.py b/uptane/clients/secondary.py index 88ea8fe..0b3ef21 100644 --- a/uptane/clients/secondary.py +++ b/uptane/clients/secondary.py @@ -30,9 +30,11 @@ import zipfile # to expand the metadata archive retrieved from the Primary import hashlib import iso8601 +import six import tuf.formats import tuf.keys +import tuf.keydb as key_database import tuf.client.updater import tuf.repository_tool as rt @@ -564,8 +566,108 @@ def fully_validate_metadata(self): ENDCOLORS) continue + if validated_targets_for_this_ecu: + self.validated_targets_for_this_ecu = validated_targets_for_this_ecu - self.validated_targets_for_this_ecu = validated_targets_for_this_ecu + + + + + def partial_validate_metadata(self): + """ + + This validates and processes the metadata, determining what firmware + the Director has instructed this partial-verification Secondary ECU to + install. + The given metadata replaces this client's current Director metadata if + the given metadata is valid -- i.e. if the metadata: + - is signed by a key matching self.director_public_key + - and is not expired (current date is before metadata's expiration date) + - and does not have an older version number than this client has + previously seen -- i.e. is not a rollback) + Otherwise, an exception is raised indicating that the metadata is not + valid. + Further, if the metadata is valid, this function then updates + self.validated_target_for_this_ecu if the metadata also lists a target + for this ECU (i.e. includes a target with field "ecu_serial" set to this + ECU's serial number) + + + None + + + tuf.BadSignatureError + if the signature over the Targets metadata is not a valid + signature by the key corresponding to self.director_public_key, or if + the key type listed in the signature does not match the key type listed + in the public key + tuf.ExpiredMetadataError + if the Targets metadata is expired + tuf.ReplayedMetadataError + if the Targets metadata has a lower version number than + the last Targets metadata this client deemed valid (rollback) + + + + May update this client's metadata (Director Targets); see + May update self.validated_targets_for_this_ecu; see + """ + + + validated_targets_for_this_ecu = [] + + upperbound_filelength = tuf.conf.DEFAULT_TARGETS_REQUIRED_LENGTH + + # Add director key in the key_database for metadata verification + try: + key_database.add_key( + self.director_public_key, repository_name=self.director_repo_name) + except tuf.KeyAlreadyExistsError: + log.debug('Key already present in the key database') + + director_obj = self.updater.repositories['director'] + + # _update_metadata downloads, verifies, and 'installs' + # the director metadata and, if it successful, than + # the current and previous metadata stores are updated. + director_obj._update_metadata('targets', upperbound_filelength) + + # TODO: If this Targets metadata file indicates that + # the Timeserver key should be rotated then reset the + # clock used to determine the expiration of metadata + # to a minimal value. It will be updated in the next cycle. + + # Is the metadata is not expired? + director_obj._ensure_not_expired( + director_obj.metadata['current']['targets'], 'targets') + + + # Do we have metadata for 'targets'? + if 'targets' not in director_obj.metadata['current']: + log.debug('No metadata for \'targtes\'. Unable to determine targets.') + return + + # To check if targets are specified by the director + is_validated_targets_from_director = False + + # Get the targets specified by the role itself. + for filepath, fileinfo in six.iteritems( + director_obj.metadata['current']['targets']['targets']): + new_target = {} + new_target['filepath'] = filepath + new_target['fileinfo'] = fileinfo + is_validated_targets_from_director = True + + if 'custom' not in new_target['fileinfo'] or \ + 'ecu_serial' not in new_target['fileinfo']['custom'] or \ + self.ecu_serial != new_target['fileinfo']['custom']['ecu_serial']: + continue + + validated_targets_for_this_ecu.append(new_target) + + # Update the secondary if targets are specified by the director + if is_validated_targets_from_director: + self.validated_targets_for_this_ecu = validated_targets_for_this_ecu @@ -602,18 +704,56 @@ def get_validated_target_info(self, target_filepath): def process_metadata(self, metadata_archive_fname): """ - Expand the metadata archive using _expand_metadata_archive() - Validate metadata files using fully_validate_metadata() - Select the Director targets.json file - Pick out the target file(s) with our ECU serial listed - Fully validate the metadata for the target file(s) + Runs either partial or full metadata verification, based on the + value of self.partial_verifying. + Note that in both cases, the use of files and archives is not key. Keep an + eye on the procedure without regard to them. The central idea is to take + the metadata pointed at by the argument here as untrusted and verify it + using the full verification or partial verification algorithms from the + Uptane Implementation Specification. It's generally expected that this + metadata comes to the Secondary from the Primary, originally from the + Director and Image repositories, but the way it gets here does not matter + as long as it checks out as trustworthy. + + Full: + The given filename, metadata_archive_fname, should point to an archive of all + metadata necessary to perform full verification, such as is produced by + primary.save_distributable_metadata_files(). + process_metadata expands this archive to a local directory where + repository files are expected to be found (the 'unverified' directory in + directory self.full_client_dir). + Then, these expanded metadata files are treated as repository metadata by + the call to fully_validate_metadata(). The Director targets.json file is + selected. The target file(s) with this Secondary's ECU serial listed is + fully validated, using whatever provided metadata is necessary, by the + underlying TUF code. + + Partial: + The given filename, metadata_archive_fname, should point to a single metadata + role file, the Director's Targets role. The signature on the Targets role + file is validated against the Director's public key + (self.director_public_key). If the signature is valid, the new Targets + role file is trusted, else it is discarded and TUF raises a + tuf.BadSignatureError. + (Additional protections come from the Primary + having vetted the file for us using full verification, as long as the + Primary is trustworthy.) + From the trusted Targets role file, the target with this Secondary's + ECU identifier/serial listed is chosen, and the metadata describing that + target (hash, length, etc.) is extracted from the metadata file and + taken as the trustworthy description of the targets file to be installed + on this Secondary. """ + tuf.formats.RELPATH_SCHEMA.check_match(metadata_archive_fname) self._expand_metadata_archive(metadata_archive_fname) - # This entails using the local metadata files as a repository. - self.fully_validate_metadata() + # This verification entails using the local metadata files as a repository. + if self.partial_verifying: + self.partial_validate_metadata() + else: + self.fully_validate_metadata()