1
1
import logging
2
+ from typing import Optional , Union
2
3
import os
3
4
import sys
4
5
import unittest
5
6
from datetime import datetime
6
7
7
8
from tuf import exceptions
8
- from tuf .api .metadata import Metadata
9
- from tuf .ngclient ._internal .trusted_metadata_set import (
10
- TrustedMetadataSet
11
- )
9
+ from tuf .api .metadata import Metadata , MetaFile
10
+ from tuf .ngclient ._internal .trusted_metadata_set import TrustedMetadataSet
11
+
12
12
from securesystemslib .signer import SSlibSigner
13
13
from securesystemslib .interface import (
14
14
import_ed25519_privatekey_from_file ,
@@ -48,14 +48,77 @@ def setUpClass(cls):
48
48
def setUp (self ) -> None :
49
49
self .trusted_set = TrustedMetadataSet (self .metadata ["root" ])
50
50
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" ])
51
+ def _root_updated_and_update_timestamp (
52
+ self , timestamp_bytes : Optional [bytes ] = None
53
+ ):
54
+ """Finsh root update and update timestamp with passed timestamp_bytes.
55
+
56
+ Args:
57
+ timestamp_bytes:
58
+ Bytes used when calling trusted_set.update_timestamp().
59
+ Default self.metadata["timestamp"].
54
60
55
- def _update_all_besides_targets (self ):
61
+ """
62
+ timestamp_bytes = timestamp_bytes or self .metadata ["timestamp" ]
56
63
self .trusted_set .root_update_finished ()
57
- self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
58
- self .trusted_set .update_snapshot (self .metadata ["snapshot" ])
64
+ self .trusted_set .update_timestamp (timestamp_bytes )
65
+
66
+
67
+ def _update_all_besides_targets (
68
+ self ,
69
+ timestamp_bytes : Optional [bytes ] = None ,
70
+ snapshot_bytes : Optional [bytes ] = None ,
71
+ ):
72
+ """Update all metadata roles besides targets.
73
+
74
+ Args:
75
+ timestamp_bytes:
76
+ Bytes used when calling trusted_set.update_timestamp().
77
+ Default self.metadata["timestamp"].
78
+ snapshot_bytes:
79
+ Bytes used when calling trusted_set.update_snapshot().
80
+ Default self.metadata["snapshot"].
81
+
82
+ """
83
+ self ._root_updated_and_update_timestamp (timestamp_bytes )
84
+ snapshot_bytes = snapshot_bytes or self .metadata ["snapshot" ]
85
+ self .trusted_set .update_snapshot (snapshot_bytes )
86
+
87
+ def _modify_timestamp_meta (self , version : Optional [int ] = 1 ):
88
+ """Remove hashes and length from timestamp.meta["snapshot.json"].
89
+ Create a timestamp.meta["snapshot.json"] containing only version.
90
+
91
+ Args:
92
+ version:
93
+ Version used when instantiating MetaFile for timestamp.meta.
94
+
95
+ """
96
+ timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
97
+ timestamp .signed .meta ["snapshot.json" ] = MetaFile (version )
98
+ timestamp .sign (self .keystore ["timestamp" ])
99
+ return timestamp .to_bytes ()
100
+
101
+ def _modify_snapshot_meta (
102
+ self , version : Union [int , None ] = 1 , length : Optional [int ]= None
103
+ ):
104
+ """Modify hashes and length from snapshot_meta.meta["snapshot.json"].
105
+ If version and length is None, then snapshot meta will be an empty dictionary.
106
+
107
+ Args:
108
+ version:
109
+ Version used when instantiating MetaFile for snapshot.meta.
110
+ length:
111
+ Length used when instantiating MetaFile for snapshot.meta.
112
+
113
+ """
114
+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
115
+ if version is None and length is None :
116
+ snapshot .signed .meta = {}
117
+ else :
118
+ for metafile_path in snapshot .signed .meta :
119
+ snapshot .signed .meta [metafile_path ] = MetaFile (version , length )
120
+ snapshot .sign (self .keystore ["snapshot" ])
121
+ return snapshot .to_bytes ()
59
122
60
123
def test_update (self ):
61
124
self .trusted_set .root_update_finished ()
@@ -183,21 +246,23 @@ def test_root_update_finished_expired(self):
183
246
184
247
185
248
def test_update_timestamp_new_timestamp_ver_below_trusted_ver (self ):
186
- self ._root_update_finished_and_update_timestamp ()
187
249
# new_timestamp.version < trusted_timestamp.version
188
- self .trusted_set .timestamp .signed .version = 2
250
+ timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
251
+ timestamp .signed .version = 3
252
+ timestamp .sign (self .keystore ["timestamp" ])
253
+ self ._root_updated_and_update_timestamp (timestamp .to_bytes ())
189
254
with self .assertRaises (exceptions .ReplayedMetadataError ):
190
255
self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
191
256
192
257
def test_update_timestamp_snapshot_ver_below_trusted_snapshot_ver (self ):
193
- self ._root_update_finished_and_update_timestamp ()
258
+ modified_timestamp = self ._modify_timestamp_meta (version = 3 )
259
+ self ._root_updated_and_update_timestamp (modified_timestamp )
194
260
# new_timestamp.snapshot.version < trusted_timestamp.snapshot.version
195
- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].version = 2
196
261
with self .assertRaises (exceptions .ReplayedMetadataError ):
197
262
self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
198
263
199
264
def test_update_timestamp_expired (self ):
200
- self ._root_update_finished_and_update_timestamp ()
265
+ self .trusted_set . root_update_finished ()
201
266
# new_timestamp has expired
202
267
timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
203
268
timestamp .signed .expires = datetime (1970 , 1 , 1 )
@@ -207,70 +272,86 @@ def test_update_timestamp_expired(self):
207
272
208
273
209
274
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 = []
275
+ modified_timestamp = self ._modify_timestamp_meta ()
276
+ self ._root_updated_and_update_timestamp (modified_timestamp )
277
+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
278
+ snapshot .signatures .clear ()
213
279
with self .assertRaises (exceptions .UnsignedMetadataError ):
214
- self .trusted_set .update_snapshot (self . metadata [ " snapshot" ] )
280
+ self .trusted_set .update_snapshot (snapshot . to_bytes () )
215
281
216
282
def test_update_snapshot_version_different_timestamp_snapshot_version (self ):
217
- self ._root_update_finished_and_update_timestamp ()
283
+ modified_timestamp = self ._modify_timestamp_meta (version = 2 )
284
+ self ._root_updated_and_update_timestamp (modified_timestamp )
218
285
# new_snapshot.version != trusted timestamp.meta["snapshot"].version
219
- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].version = 2
286
+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
287
+ snapshot .signed .version = 3
288
+ snapshot .sign (self .keystore ["snapshot" ])
220
289
with self .assertRaises (exceptions .BadVersionNumberError ):
221
- self .trusted_set .update_snapshot (self . metadata [ " snapshot" ] )
290
+ self .trusted_set .update_snapshot (snapshot . to_bytes () )
222
291
223
292
def test_update_snapshot_after_successful_update_new_snapshot_no_meta (self ):
224
- self ._update_all_besides_targets ()
293
+ modified_timestamp = self ._modify_timestamp_meta ()
294
+ self ._update_all_besides_targets (modified_timestamp )
225
295
# Test removing a meta_file in new_snapshot compared to the old snapshot
226
296
snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
227
297
snapshot .signed .meta = {}
228
298
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
231
299
with self .assertRaises (exceptions .RepositoryError ):
232
300
self .trusted_set .update_snapshot (snapshot .to_bytes ())
233
301
234
302
def test_update_snapshot_after_succesfull_update_new_snapshot_meta_version_different (self ):
235
- self ._update_all_besides_targets ()
303
+ modified_timestamp = self ._modify_timestamp_meta ()
304
+ self ._root_updated_and_update_timestamp (modified_timestamp )
236
305
# snapshot.meta["project1"].version != new_snapshot.meta["project1"].version
237
- for metafile in self .trusted_set .snapshot .signed .meta .values ():
238
- metafile .version += 1
306
+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
307
+ for metafile_path in snapshot .signed .meta .keys ():
308
+ snapshot .signed .meta [metafile_path ].version += 1
309
+ snapshot .sign (self .keystore ["snapshot" ])
310
+ self .trusted_set .update_snapshot (snapshot .to_bytes ())
239
311
with self .assertRaises (exceptions .BadVersionNumberError ):
240
312
self .trusted_set .update_snapshot (self .metadata ["snapshot" ])
241
313
242
- def test_update_snapshot_after_succesfull_expired_new_snapshot (self ):
243
- self ._update_all_besides_targets ()
314
+ def test_update_snapshot_expired_new_snapshot (self ):
315
+ modified_timestamp = self ._modify_timestamp_meta ()
316
+ self ._root_updated_and_update_timestamp (modified_timestamp )
244
317
# new_snapshot has expired
245
318
snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
246
319
snapshot .signed .expires = datetime (1970 , 1 , 1 )
247
320
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
250
321
with self .assertRaises (exceptions .ExpiredMetadataError ):
251
322
self .trusted_set .update_snapshot (snapshot .to_bytes ())
252
323
253
324
254
325
def test_update_targets_no_meta_in_snapshot (self ):
255
- self ._update_all_besides_targets ()
326
+ modified_timestamp = self ._modify_timestamp_meta ()
327
+ modified_snapshot = self ._modify_snapshot_meta (version = None )
328
+ self ._update_all_besides_targets (
329
+ timestamp_bytes = modified_timestamp ,
330
+ snapshot_bytes = modified_snapshot
331
+ )
256
332
# remove meta information with information about targets from snapshot
257
- self .trusted_set .snapshot .signed .meta = {}
258
333
with self .assertRaises (exceptions .RepositoryError ):
259
334
self .trusted_set .update_targets (self .metadata ["targets" ])
260
335
261
336
def test_update_targets_hash_different_than_snapshot_meta_hash (self ):
262
- self ._update_all_besides_targets ()
337
+ modified_timestamp = self ._modify_timestamp_meta ()
338
+ modified_snapshot = self ._modify_snapshot_meta (version = 1 , length = 1 )
339
+ self ._update_all_besides_targets (
340
+ timestamp_bytes = modified_timestamp ,
341
+ snapshot_bytes = modified_snapshot
342
+ )
263
343
# 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" }
266
344
with self .assertRaises (exceptions .RepositoryError ):
267
345
self .trusted_set .update_targets (self .metadata ["targets" ])
268
346
269
347
def test_update_targets_version_different_snapshot_meta_version (self ):
270
- self ._update_all_besides_targets ()
348
+ modified_timestamp = self ._modify_timestamp_meta ()
349
+ modified_snapshot = self ._modify_snapshot_meta (version = 2 )
350
+ self ._update_all_besides_targets (
351
+ timestamp_bytes = modified_timestamp ,
352
+ snapshot_bytes = modified_snapshot
353
+ )
271
354
# 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
274
355
with self .assertRaises (exceptions .BadVersionNumberError ):
275
356
self .trusted_set .update_targets (self .metadata ["targets" ])
276
357
0 commit comments