11import logging
2+ from typing import Optional , Union
23import os
34import sys
45import unittest
56from datetime import datetime
67
78from tuf import exceptions
8- from tuf .api .metadata import Metadata
9+ from tuf .api .metadata import Metadata , MetaFile
910from tuf .ngclient ._internal .trusted_metadata_set import (
1011 TrustedMetadataSet
1112)
13+ from tuf .api .serialization .json import JSONSerializer
1214from securesystemslib .signer import SSlibSigner
1315from securesystemslib .interface import (
1416 import_ed25519_privatekey_from_file ,
@@ -48,14 +50,77 @@ def setUpClass(cls):
4850 def setUp (self ) -> None :
4951 self .trusted_set = TrustedMetadataSet (self .metadata ["root" ])
5052
51- def _root_update_finished_and_update_timestamp (self ):
52- self .trusted_set .root_update_finished ()
53- self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
53+ def _root_updated_and_update_timestamp (
54+ self , timestamp_bytes : Optional [bytes ] = None
55+ ):
56+ """Finsh root update and update timestamp with passed timestamp_bytes.
57+
58+ Args:
59+ timestamp_bytes:
60+ Bytes used when calling trusted_set.update_timestamp().
61+ Default self.metadata["timestamp"].
5462
55- def _update_all_besides_targets (self ):
63+ """
64+ timestamp_bytes = timestamp_bytes or self .metadata ["timestamp" ]
5665 self .trusted_set .root_update_finished ()
57- self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
58- self .trusted_set .update_snapshot (self .metadata ["snapshot" ])
66+ self .trusted_set .update_timestamp (timestamp_bytes )
67+
68+
69+ def _update_all_besides_targets (
70+ self ,
71+ timestamp_bytes : Optional [bytes ] = None ,
72+ snapshot_bytes : Optional [bytes ] = None ,
73+ ):
74+ """Update all metadata roles besides targets.
75+ q
76+ Args:
77+ timestamp_bytes:
78+ Bytes used when calling trusted_set.update_timestamp().
79+ Default self.metadata["timestamp"].
80+ snapshot_bytes:
81+ Bytes used when calling trusted_set.update_snapshot().
82+ Default self.metadata["snapshot"].
83+
84+ """
85+ self ._root_updated_and_update_timestamp (timestamp_bytes )
86+ snapshot_bytes = snapshot_bytes or self .metadata ["snapshot" ]
87+ self .trusted_set .update_snapshot (snapshot_bytes )
88+
89+ def _modify_timestamp_meta (self , version : Optional [int ] = 1 ):
90+ """Remove hashes and length from timestamp.meta["snapshot.json"].
91+ Create a timestamp.meta["snapshot.json"] containing only version.
92+
93+ Args:
94+ version:
95+ Version used when instantiating MetaFile for timestamp.meta.
96+
97+ """
98+ timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
99+ timestamp .signed .meta ["snapshot.json" ] = MetaFile (version )
100+ timestamp .sign (self .keystore ["timestamp" ])
101+ return timestamp .to_bytes ()
102+
103+ def _modify_snapshot_meta (
104+ self , version : Union [int , None ] = 1 , length : Optional [int ]= None
105+ ):
106+ """Modify hashes and length from snapshot_meta.meta["snapshot.json"].
107+ If version and length is None, then snapshot meta will be an empty dictionary.
108+
109+ Args:
110+ version:
111+ Version used when instantiating MetaFile for snapshot.meta.
112+ length:
113+ Length used when instantiating MetaFile for snapshot.meta.
114+
115+ """
116+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
117+ if version is None and length is None :
118+ snapshot .signed .meta = {}
119+ else :
120+ for metafile_path in snapshot .signed .meta :
121+ snapshot .signed .meta [metafile_path ] = MetaFile (version , length )
122+ snapshot .sign (self .keystore ["snapshot" ])
123+ return snapshot .to_bytes ()
59124
60125 def test_update (self ):
61126 self .trusted_set .root_update_finished ()
@@ -183,21 +248,23 @@ def test_root_update_finished_expired(self):
183248
184249
185250 def test_update_timestamp_new_timestamp_ver_below_trusted_ver (self ):
186- self ._root_update_finished_and_update_timestamp ()
187251 # new_timestamp.version < trusted_timestamp.version
188- self .trusted_set .timestamp .signed .version = 2
252+ timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
253+ timestamp .signed .version = 3
254+ timestamp .sign (self .keystore ["timestamp" ])
255+ self ._root_updated_and_update_timestamp (timestamp .to_bytes ())
189256 with self .assertRaises (exceptions .ReplayedMetadataError ):
190257 self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
191258
192259 def test_update_timestamp_snapshot_ver_below_trusted_snapshot_ver (self ):
193- self ._root_update_finished_and_update_timestamp ()
260+ modified_timestamp = self ._modify_timestamp_meta (version = 3 )
261+ self ._root_updated_and_update_timestamp (modified_timestamp )
194262 # new_timestamp.snapshot.version < trusted_timestamp.snapshot.version
195- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].version = 2
196263 with self .assertRaises (exceptions .ReplayedMetadataError ):
197264 self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
198265
199266 def test_update_timestamp_expired (self ):
200- self ._root_update_finished_and_update_timestamp ()
267+ self .trusted_set . root_update_finished ()
201268 # new_timestamp has expired
202269 timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
203270 timestamp .signed .expires = datetime (1970 , 1 , 1 )
@@ -207,70 +274,86 @@ def test_update_timestamp_expired(self):
207274
208275
209276 def test_update_snapshot_cannot_verify_snapshot_with_threshold (self ):
210- self ._root_update_finished_and_update_timestamp ()
211- # remove keyids representing snapshot signatures from root data
212- self .trusted_set .root .signed .roles ["snapshot" ].keyids = []
277+ modified_timestamp = self ._modify_timestamp_meta ()
278+ self ._root_updated_and_update_timestamp (modified_timestamp )
279+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
280+ snapshot .signatures .clear ()
213281 with self .assertRaises (exceptions .UnsignedMetadataError ):
214- self .trusted_set .update_snapshot (self . metadata [ " snapshot" ] )
282+ self .trusted_set .update_snapshot (snapshot . to_bytes () )
215283
216284 def test_update_snapshot_version_different_timestamp_snapshot_version (self ):
217- self ._root_update_finished_and_update_timestamp ()
285+ modified_timestamp = self ._modify_timestamp_meta (version = 2 )
286+ self ._root_updated_and_update_timestamp (modified_timestamp )
218287 # new_snapshot.version != trusted timestamp.meta["snapshot"].version
219- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].version = 2
288+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
289+ snapshot .signed .version = 3
290+ snapshot .sign (self .keystore ["snapshot" ])
220291 with self .assertRaises (exceptions .BadVersionNumberError ):
221- self .trusted_set .update_snapshot (self . metadata [ " snapshot" ] )
292+ self .trusted_set .update_snapshot (snapshot . to_bytes () )
222293
223294 def test_update_snapshot_after_successful_update_new_snapshot_no_meta (self ):
224- self ._update_all_besides_targets ()
295+ modified_timestamp = self ._modify_timestamp_meta ()
296+ self ._update_all_besides_targets (modified_timestamp )
225297 # Test removing a meta_file in new_snapshot compared to the old snapshot
226298 snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
227299 snapshot .signed .meta = {}
228300 snapshot .sign (self .keystore ["snapshot" ])
229- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].hashes = None
230- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].length = None
231301 with self .assertRaises (exceptions .RepositoryError ):
232302 self .trusted_set .update_snapshot (snapshot .to_bytes ())
233303
234304 def test_update_snapshot_after_succesfull_update_new_snapshot_meta_version_different (self ):
235- self ._update_all_besides_targets ()
305+ modified_timestamp = self ._modify_timestamp_meta ()
306+ self ._root_updated_and_update_timestamp (modified_timestamp )
236307 # snapshot.meta["project1"].version != new_snapshot.meta["project1"].version
237- for metafile in self .trusted_set .snapshot .signed .meta .values ():
238- metafile .version += 1
308+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
309+ for metafile_path in snapshot .signed .meta .keys ():
310+ snapshot .signed .meta [metafile_path ].version += 1
311+ snapshot .sign (self .keystore ["snapshot" ])
312+ self .trusted_set .update_snapshot (snapshot .to_bytes ())
239313 with self .assertRaises (exceptions .BadVersionNumberError ):
240314 self .trusted_set .update_snapshot (self .metadata ["snapshot" ])
241315
242- def test_update_snapshot_after_succesfull_expired_new_snapshot (self ):
243- self ._update_all_besides_targets ()
316+ def test_update_snapshot_expired_new_snapshot (self ):
317+ modified_timestamp = self ._modify_timestamp_meta ()
318+ self ._root_updated_and_update_timestamp (modified_timestamp )
244319 # new_snapshot has expired
245320 snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
246321 snapshot .signed .expires = datetime (1970 , 1 , 1 )
247322 snapshot .sign (self .keystore ["snapshot" ])
248- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].hashes = None
249- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].length = None
250323 with self .assertRaises (exceptions .ExpiredMetadataError ):
251324 self .trusted_set .update_snapshot (snapshot .to_bytes ())
252325
253326
254327 def test_update_targets_no_meta_in_snapshot (self ):
255- self ._update_all_besides_targets ()
328+ modified_timestamp = self ._modify_timestamp_meta ()
329+ modified_snapshot = self ._modify_snapshot_meta (version = None )
330+ self ._update_all_besides_targets (
331+ timestamp_bytes = modified_timestamp ,
332+ snapshot_bytes = modified_snapshot
333+ )
256334 # remove meta information with information about targets from snapshot
257- self .trusted_set .snapshot .signed .meta = {}
258335 with self .assertRaises (exceptions .RepositoryError ):
259336 self .trusted_set .update_targets (self .metadata ["targets" ])
260337
261338 def test_update_targets_hash_different_than_snapshot_meta_hash (self ):
262- self ._update_all_besides_targets ()
339+ modified_timestamp = self ._modify_timestamp_meta ()
340+ modified_snapshot = self ._modify_snapshot_meta (version = 1 , length = 1 )
341+ self ._update_all_besides_targets (
342+ timestamp_bytes = modified_timestamp ,
343+ snapshot_bytes = modified_snapshot
344+ )
263345 # observed_hash != stored hash in snapshot meta for targets
264- for target_path in self .trusted_set .snapshot .signed .meta .keys ():
265- self .trusted_set .snapshot .signed .meta [target_path ].hashes = {"sha256" : "b" }
266346 with self .assertRaises (exceptions .RepositoryError ):
267347 self .trusted_set .update_targets (self .metadata ["targets" ])
268348
269349 def test_update_targets_version_different_snapshot_meta_version (self ):
270- self ._update_all_besides_targets ()
350+ modified_timestamp = self ._modify_timestamp_meta ()
351+ modified_snapshot = self ._modify_snapshot_meta (version = 2 )
352+ self ._update_all_besides_targets (
353+ timestamp_bytes = modified_timestamp ,
354+ snapshot_bytes = modified_snapshot
355+ )
271356 # new_delegate.signed.version != meta.version stored in snapshot
272- for target_path in self .trusted_set .snapshot .signed .meta .keys ():
273- self .trusted_set .snapshot .signed .meta [target_path ].version = 2
274357 with self .assertRaises (exceptions .BadVersionNumberError ):
275358 self .trusted_set .update_targets (self .metadata ["targets" ])
276359
0 commit comments