Skip to main content

tuf/
database.rs

1//! Components needed to verify TUF metadata and targets.
2
3use chrono::{offset::Utc, DateTime};
4use std::cmp::Ordering;
5use std::collections::{HashMap, HashSet};
6use std::marker::PhantomData;
7
8use crate::crypto::PublicKey;
9use crate::error::Error;
10use crate::metadata::{
11    Delegations, Metadata, MetadataPath, MetadataVersion, RawSignedMetadata, RawSignedMetadataSet,
12    RootMetadata, SnapshotMetadata, TargetDescription, TargetPath, TargetsMetadata,
13    TimestampMetadata,
14};
15use crate::pouf::Pouf;
16use crate::verify::{self, Verified};
17use crate::Result;
18
19/// Contains trusted TUF metadata and can be used to verify other metadata and targets.
20#[derive(Debug)]
21pub struct Database<D: Pouf> {
22    trusted_root: Verified<RootMetadata>,
23    trusted_targets: Option<Verified<TargetsMetadata>>,
24    trusted_snapshot: Option<Verified<SnapshotMetadata>>,
25    trusted_timestamp: Option<Verified<TimestampMetadata>>,
26    trusted_delegations: HashMap<MetadataPath, Verified<TargetsMetadata>>,
27    pouf: PhantomData<D>,
28}
29
30impl<D: Pouf> Database<D> {
31    /// Create a new [`Database`] struct from a set of trusted root keys that are used to verify
32    /// the signed metadata. The signed root metadata must be signed with at least a
33    /// `root_threshold` of the provided root_keys. It is not necessary for the root metadata to
34    /// contain these keys.
35    pub fn from_root_with_trusted_keys<'a, I>(
36        raw_root: &RawSignedMetadata<D, RootMetadata>,
37        root_threshold: u32,
38        root_keys: I,
39    ) -> Result<Self>
40    where
41        I: IntoIterator<Item = &'a PublicKey>,
42    {
43        let verified_root = {
44            // Make sure the keys signed the root.
45            let new_root = verify::verify_signatures(
46                &MetadataPath::root(),
47                raw_root,
48                root_threshold,
49                root_keys,
50            )?;
51
52            // Make sure the root signed itself.
53            verify::verify_signatures(
54                &MetadataPath::root(),
55                raw_root,
56                new_root.root().threshold(),
57                new_root.keys().iter().filter_map(|(k, v)| {
58                    if new_root.root().key_ids().contains(k) {
59                        Some(v)
60                    } else {
61                        None
62                    }
63                }),
64            )?
65        };
66
67        Ok(Database {
68            trusted_root: verified_root,
69            trusted_snapshot: None,
70            trusted_targets: None,
71            trusted_timestamp: None,
72            trusted_delegations: HashMap::new(),
73            pouf: PhantomData,
74        })
75    }
76
77    /// Create a new [`Database`] struct from a piece of metadata that is assumed to be trusted.
78    ///
79    /// **WARNING**: This is trust-on-first-use (TOFU) and offers weaker security guarantees than
80    /// the related method [`Database::from_root_with_trusted_keys`] because this method needs to
81    /// deserialize `raw_root` before we have verified it has been signed properly. This exposes us
82    /// to potential parser exploits. This method should only be used if the metadata is loaded from
83    /// a trusted source.
84    pub fn from_trusted_root(raw_root: &RawSignedMetadata<D, RootMetadata>) -> Result<Self> {
85        let verified_root = {
86            // **WARNING**: By deserializing the metadata before verification, we are exposing us
87            // to parser exploits.
88            let unverified_root = raw_root.parse_untrusted()?.assume_valid()?;
89
90            // Make sure the root signed itself.
91            verify::verify_signatures(
92                &MetadataPath::root(),
93                raw_root,
94                unverified_root.root().threshold(),
95                unverified_root.root_keys(),
96            )?
97        };
98
99        Ok(Database {
100            trusted_root: verified_root,
101            trusted_snapshot: None,
102            trusted_targets: None,
103            trusted_timestamp: None,
104            trusted_delegations: HashMap::new(),
105            pouf: PhantomData,
106        })
107    }
108
109    /// Create a new [`Database`] struct from a set of metadata that is assumed to be trusted. The
110    /// signed root metadata in the `metadata_set` must be signed with at least a `root_threshold`
111    /// of the provided root_keys. It is not necessary for the root metadata to contain these keys.
112    pub fn from_metadata_with_trusted_keys<'a, I>(
113        metadata_set: &RawSignedMetadataSet<D>,
114        root_threshold: u32,
115        root_keys: I,
116    ) -> Result<Self>
117    where
118        I: IntoIterator<Item = &'a PublicKey>,
119    {
120        Self::from_metadata_with_trusted_keys_and_start_time(
121            &Utc::now(),
122            metadata_set,
123            root_threshold,
124            root_keys,
125        )
126    }
127
128    /// Create a new [`Database`] struct from a set of metadata that is assumed to be trusted. The
129    /// signed root metadata in the `metadata_set` must be signed with at least a `root_threshold`
130    /// of the provided root_keys. It is not necessary for the root metadata to contain these keys.
131    pub fn from_metadata_with_trusted_keys_and_start_time<'a, I>(
132        start_time: &DateTime<Utc>,
133        metadata_set: &RawSignedMetadataSet<D>,
134        root_threshold: u32,
135        root_keys: I,
136    ) -> Result<Self>
137    where
138        I: IntoIterator<Item = &'a PublicKey>,
139    {
140        let mut db = if let Some(root) = metadata_set.root() {
141            Database::from_root_with_trusted_keys(root, root_threshold, root_keys)?
142        } else {
143            return Err(Error::MetadataNotFound {
144                path: MetadataPath::root(),
145                version: MetadataVersion::None,
146            });
147        };
148
149        db.update_metadata_after_root(start_time, metadata_set)?;
150
151        Ok(db)
152    }
153
154    /// Create a new [`Database`] struct from a set of metadata that is assumed to be trusted.
155    ///
156    /// **WARNING**: This is trust-on-first-use (TOFU) and offers weaker security guarantees than
157    /// the related method [`Database::from_metadata_with_trusted_keys`] because this method needs
158    /// to deserialize the root metadata from `metadata_set` before we have verified it has been
159    /// signed properly. This exposes us to potential parser exploits. This method should only be
160    /// used if the metadata is loaded from a trusted source.
161    pub fn from_trusted_metadata(metadata_set: &RawSignedMetadataSet<D>) -> Result<Self> {
162        Self::from_trusted_metadata_with_start_time(metadata_set, &Utc::now())
163    }
164
165    /// Create a new [`Database`] struct from a set of metadata that is assumed to be trusted.
166    ///
167    /// **WARNING**: This is trust-on-first-use (TOFU) and offers weaker security guarantees than
168    /// the related method [`Database::from_metadata_with_trusted_keys`] because this method needs
169    /// to deserialize the root metadata from `metadata_set` before we have verified it has been
170    /// signed properly. This exposes us to potential parser exploits. This method should only be
171    /// used if the metadata is loaded from a trusted source.
172    pub fn from_trusted_metadata_with_start_time(
173        metadata_set: &RawSignedMetadataSet<D>,
174        start_time: &DateTime<Utc>,
175    ) -> Result<Self> {
176        let mut db = if let Some(root) = metadata_set.root() {
177            Database::from_trusted_root(root)?
178        } else {
179            return Err(Error::MetadataNotFound {
180                path: MetadataPath::root(),
181                version: MetadataVersion::None,
182            });
183        };
184
185        db.update_metadata_after_root(start_time, metadata_set)?;
186
187        Ok(db)
188    }
189
190    /// An immutable reference to the root metadata.
191    pub fn trusted_root(&self) -> &Verified<RootMetadata> {
192        &self.trusted_root
193    }
194
195    /// An immutable reference to the optional targets metadata.
196    pub fn trusted_targets(&self) -> Option<&Verified<TargetsMetadata>> {
197        self.trusted_targets.as_ref()
198    }
199
200    /// An immutable reference to the optional snapshot metadata.
201    pub fn trusted_snapshot(&self) -> Option<&Verified<SnapshotMetadata>> {
202        self.trusted_snapshot.as_ref()
203    }
204
205    /// An immutable reference to the optional timestamp metadata.
206    pub fn trusted_timestamp(&self) -> Option<&Verified<TimestampMetadata>> {
207        self.trusted_timestamp.as_ref()
208    }
209
210    /// An immutable reference to the delegated metadata.
211    pub fn trusted_delegations(&self) -> &HashMap<MetadataPath, Verified<TargetsMetadata>> {
212        &self.trusted_delegations
213    }
214
215    /// Verify and update metadata. Returns true if any of the metadata was updated.
216    pub fn update_metadata(&mut self, metadata: &RawSignedMetadataSet<D>) -> Result<bool> {
217        self.update_metadata_with_start_time(metadata, &Utc::now())
218    }
219
220    /// Verify and update metadata. Returns true if any of the metadata was updated.
221    pub fn update_metadata_with_start_time(
222        &mut self,
223        metadata: &RawSignedMetadataSet<D>,
224        start_time: &DateTime<Utc>,
225    ) -> Result<bool> {
226        let updated = if let Some(root) = metadata.root() {
227            self.update_root(root)?;
228            true
229        } else {
230            false
231        };
232
233        if self.update_metadata_after_root(start_time, metadata)? {
234            Ok(true)
235        } else {
236            Ok(updated)
237        }
238    }
239
240    fn update_metadata_after_root(
241        &mut self,
242        start_time: &DateTime<Utc>,
243        metadata_set: &RawSignedMetadataSet<D>,
244    ) -> Result<bool> {
245        let mut updated = false;
246        if let Some(timestamp) = metadata_set.timestamp() {
247            if self.update_timestamp(start_time, timestamp)?.is_some() {
248                updated = true;
249            }
250        }
251
252        if let Some(snapshot) = metadata_set.snapshot() {
253            if self.update_snapshot(start_time, snapshot)? {
254                updated = true;
255            }
256        }
257
258        if let Some(targets) = metadata_set.targets() {
259            if self.update_targets(start_time, targets)? {
260                updated = true;
261            }
262        }
263
264        Ok(updated)
265    }
266
267    /// Verify and update the root metadata.
268    pub fn update_root(&mut self, raw_root: &RawSignedMetadata<D, RootMetadata>) -> Result<()> {
269        let verified = {
270            let trusted_root = &self.trusted_root;
271
272            /////////////////////////////////////////
273            // TUF-1.0.5 §5.1.3:
274            //
275            //     Check signatures. Version N+1 of the root metadata file MUST have been signed
276            //     by: (1) a threshold of keys specified in the trusted root metadata file (version
277            //     N), and (2) a threshold of keys specified in the new root metadata file being
278            //     validated (version N+1). If version N+1 is not signed as required, discard it,
279            //     abort the update cycle, and report the signature failure. On the next update
280            //     cycle, begin at step 0 and version N of the root metadata file.  Verify the
281            //     trusted root signed the new root.
282            let new_root = verify::verify_signatures(
283                &MetadataPath::root(),
284                raw_root,
285                trusted_root.root().threshold(),
286                trusted_root.root_keys(),
287            )?;
288
289            // Verify the new root signed itself.
290            let new_root = verify::verify_signatures(
291                &MetadataPath::root(),
292                raw_root,
293                new_root.root().threshold(),
294                new_root.root_keys(),
295            )?;
296
297            /////////////////////////////////////////
298            // TUF-1.0.5 §5.1.4:
299            //
300            //     Check for a rollback attack. The version number of the trusted root metadata
301            //     file (version N) must be less than or equal to the version number of the new
302            //     root metadata file (version N+1). Effectively, this means checking that the
303            //     version number signed in the new root metadata file is indeed N+1. If the
304            //     version of the new root metadata file is less than the trusted metadata file,
305            //     discard it, abort the update cycle, and report the rollback attack. On the next
306            //     update cycle, begin at step 0 and version N of the root metadata file.
307
308            let next_root_version = trusted_root.version().checked_add(1).ok_or_else(|| {
309                Error::MetadataVersionMustBeSmallerThanMaxU32(MetadataPath::root())
310            })?;
311
312            if new_root.version() != next_root_version {
313                return Err(Error::AttemptedMetadataRollBack {
314                    role: MetadataPath::root(),
315                    trusted_version: trusted_root.version(),
316                    new_version: new_root.version(),
317                });
318            }
319
320            /////////////////////////////////////////
321            // TUF-1.0.5 §5.1.5:
322            //
323            //     Note that the expiration of the new (intermediate) root metadata file does not matter yet, because we will check for it in step 1.8.
324
325            /////////////////////////////////////////
326            // TUF-1.0.5 §5.1.8:
327            //
328            //     Check for a freeze attack. The latest known time should be lower than the
329            //     expiration timestamp in the trusted root metadata file (version N). If the
330            //     trusted root metadata file has expired, abort the update cycle, report the
331            //     potential freeze attack. On the next update cycle, begin at step 0 and version N
332            //     of the root metadata file.
333
334            // FIXME: root metadata expiration is performed in Client. We should restructure things
335            // such that it is performed here.
336
337            new_root
338        };
339
340        /////////////////////////////////////////
341        // TUF-1.0.5 §5.1.9:
342        //
343        //     If the timestamp and / or snapshot keys have been rotated, then delete the
344        //     trusted timestamp and snapshot metadata files. This is done in order to recover
345        //     from fast-forward attacks after the repository has been compromised and
346        //     recovered. A fast-forward attack happens when attackers arbitrarily increase the
347        //     version numbers of: (1) the timestamp metadata, (2) the snapshot metadata, and /
348        //     or (3) the targets, or a delegated targets, metadata file in the snapshot
349        //     metadata. Please see the Mercury paper for more details.
350
351        self.purge_metadata();
352
353        /////////////////////////////////////////
354        // TUF-1.0.5 §5.1.6:
355        //
356        //     1.6. Set the trusted root metadata file to the new root metadata file.
357
358        self.trusted_root = verified;
359
360        Ok(())
361    }
362
363    /// Verify and update the timestamp metadata.
364    ///
365    /// Returns a reference to the parsed metadata if the metadata was newer.
366    pub fn update_timestamp(
367        &mut self,
368        start_time: &DateTime<Utc>,
369        raw_timestamp: &RawSignedMetadata<D, TimestampMetadata>,
370    ) -> Result<Option<&Verified<TimestampMetadata>>> {
371        let verified = {
372            // FIXME(https://github.com/theupdateframework/specification/issues/113) Should we
373            // check if the root metadata is expired here? We do that in the other `Database::update_*`
374            // methods, but not here.
375            let trusted_root = &self.trusted_root;
376
377            /////////////////////////////////////////
378            // TUF-1.0.5 §5.2.1:
379            //
380            //     Check signatures. The new timestamp metadata file must have been signed by a
381            //     threshold of keys specified in the trusted root metadata file. If the new
382            //     timestamp metadata file is not properly signed, discard it, abort the update
383            //     cycle, and report the signature failure.
384
385            let new_timestamp = verify::verify_signatures(
386                &MetadataPath::timestamp(),
387                raw_timestamp,
388                trusted_root.timestamp().threshold(),
389                trusted_root.timestamp_keys(),
390            )?;
391
392            /////////////////////////////////////////
393            // TUF-1.0.5 §5.2.2: Check for a rollback attack.
394
395            /////////////////////////////////////////
396            // TUF-1.0.5 §5.2.2.1:
397            //
398            //     The version number of the trusted timestamp metadata file, if any, must be less
399            //     than or equal to the version number of the new timestamp metadata file. If the
400            //     new timestamp metadata file is older than the trusted timestamp metadata file,
401            //     discard it, abort the update cycle, and report the potential rollback attack.
402
403            if let Some(trusted_timestamp) = &self.trusted_timestamp {
404                match new_timestamp.version().cmp(&trusted_timestamp.version()) {
405                    Ordering::Less => {
406                        return Err(Error::AttemptedMetadataRollBack {
407                            role: MetadataPath::timestamp(),
408                            trusted_version: trusted_timestamp.version(),
409                            new_version: new_timestamp.version(),
410                        });
411                    }
412                    Ordering::Equal => {
413                        return Ok(None);
414                    }
415                    Ordering::Greater => {}
416                }
417            }
418
419            /////////////////////////////////////////
420            // TUF-1.0.5 §5.2.2.2:
421            //
422            //     The version number of the snapshot metadata file in the trusted timestamp
423            //     metadata file, if any, MUST be less than or equal to its version number in the
424            //     new timestamp metadata file. If not, discard the new timestamp metadadata file,
425            //     abort the update cycle, and report the failure.
426
427            // FIXME(#294): Implement this section.
428
429            /////////////////////////////////////////
430            // FIXME(#297): forgetting the trusted snapshot here is not part of the spec. Do we need to
431            // do it?
432
433            if let Some(trusted_snapshot) = &self.trusted_snapshot {
434                if trusted_snapshot.version() != new_timestamp.snapshot().version() {
435                    self.trusted_snapshot = None;
436                }
437            }
438
439            /////////////////////////////////////////
440            // TUF-1.0.5 §5.2.3:
441            //
442            //     Check for a freeze attack. The latest known time should be lower than the
443            //     expiration timestamp in the new timestamp metadata file. If so, the new
444            //     timestamp metadata file becomes the trusted timestamp metadata file. If the new
445            //     timestamp metadata file has expired, discard it, abort the update cycle, and
446            //     report the potential freeze attack.
447
448            if new_timestamp.expires() <= start_time {
449                return Err(Error::ExpiredMetadata {
450                    path: MetadataPath::timestamp(),
451                    expiration: *new_timestamp.expires(),
452                    now: *start_time,
453                });
454            }
455
456            new_timestamp
457        };
458
459        self.trusted_timestamp = Some(verified);
460        Ok(self.trusted_timestamp.as_ref())
461    }
462
463    /// Verify and update the snapshot metadata.
464    pub fn update_snapshot(
465        &mut self,
466        start_time: &DateTime<Utc>,
467        raw_snapshot: &RawSignedMetadata<D, SnapshotMetadata>,
468    ) -> Result<bool> {
469        let verified = {
470            /////////////////////////////////////////
471            // FIXME(https://github.com/theupdateframework/specification/issues/113) Checking if
472            // this metadata expired isn't part of the spec. Do we actually want to do this?
473            let trusted_root = self.trusted_root_unexpired(start_time)?;
474            let trusted_timestamp = self.trusted_timestamp_unexpired(start_time)?;
475
476            if let Some(trusted_snapshot) = &self.trusted_snapshot {
477                match trusted_timestamp
478                    .snapshot()
479                    .version()
480                    .cmp(&trusted_snapshot.version())
481                {
482                    Ordering::Less => {
483                        return Err(Error::AttemptedMetadataRollBack {
484                            role: MetadataPath::snapshot(),
485                            trusted_version: trusted_snapshot.version(),
486                            new_version: trusted_timestamp.snapshot().version(),
487                        });
488                    }
489                    Ordering::Equal => {
490                        return Ok(false);
491                    }
492                    Ordering::Greater => {}
493                }
494            }
495
496            /////////////////////////////////////////
497            // TUF-1.0.5 §5.3.1:
498            //
499            //     Check against timestamp metadata. The hashes and version number of the new
500            //     snapshot metadata file MUST match the hashes (if any) and version number listed
501            //     in the trusted timestamp metadata. If hashes and version do not match, discard
502            //     the new snapshot metadata, abort the update cycle, and report the failure.
503
504            // FIXME: rust-tuf checks the hash during download, but it would be better if we
505            // checked the hash here to make it easier to validate we've correctly implemented the
506            // spec.
507
508            // NOTE(https://github.com/theupdateframework/specification/pull/112): Technically
509            // we're supposed to check the version before checking the signature, but we do it
510            // afterwards. That PR proposes formally moving the version check to after signature
511            // verification.
512
513            /////////////////////////////////////////
514            // TUF-1.0.5 §5.3.2:
515            //
516            //     The new snapshot metadata file MUST have been signed by a threshold of keys
517            //     specified in the trusted root metadata file. If the new snapshot metadata file
518            //     is not signed as required, discard it, abort the update cycle, and report the
519            //     signature failure.
520
521            let new_snapshot = verify::verify_signatures(
522                &MetadataPath::snapshot(),
523                raw_snapshot,
524                trusted_root.snapshot().threshold(),
525                trusted_root.snapshot_keys(),
526            )?;
527
528            /////////////////////////////////////////
529            // FIXME(https://github.com/theupdateframework/specification/pull/112): Actually check
530            // the version.
531
532            if new_snapshot.version() != trusted_timestamp.snapshot().version() {
533                return Err(Error::WrongMetadataVersion {
534                    parent_role: MetadataPath::timestamp(),
535                    child_role: MetadataPath::snapshot(),
536                    expected_version: trusted_timestamp.snapshot().version(),
537                    new_version: new_snapshot.version(),
538                });
539            }
540
541            /////////////////////////////////////////
542            // TUF-1.0.5 §5.3.3: Check for a rollback attack.
543
544            /////////////////////////////////////////
545            // TUF-1.0.5 §5.3.3.1:
546            //
547            //     The version number of the trusted snapshot metadata file, if any, MUST be less
548            //     than or equal to the version number of the new snapshot metadata file. If the
549            //     new snapshot metadata file is older than the trusted metadata file, discard it,
550            //     abort the update cycle, and report the potential rollback attack.
551
552            if let Some(trusted_snapshot) = &self.trusted_snapshot {
553                if new_snapshot.version() < trusted_snapshot.version() {
554                    return Err(Error::AttemptedMetadataRollBack {
555                        role: MetadataPath::snapshot(),
556                        trusted_version: trusted_snapshot.version(),
557                        new_version: new_snapshot.version(),
558                    });
559                }
560            }
561
562            /////////////////////////////////////////
563            // TUF-1.0.5 §5.3.3.2:
564            //
565            //     The version number of the targets metadata file, and all delegated targets
566            //     metadata files (if any), in the trusted snapshot metadata file, if any, MUST be
567            //     less than or equal to its version number in the new snapshot metadata file.
568            //     Furthermore, any targets metadata filename that was listed in the trusted
569            //     snapshot metadata file, if any, MUST continue to be listed in the new snapshot
570            //     metadata file. If any of these conditions are not met, discard the new snapshot
571            //     metadadata file, abort the update cycle, and report the failure.
572
573            // FIXME(#295): Implement this section.
574
575            /////////////////////////////////////////
576            // TUF-1.0.5 §5.3.4:
577            //
578            //     Check for a freeze attack. The latest known time should be lower than the
579            //     expiration timestamp in the new snapshot metadata file. If so, the new snapshot
580            //     metadata file becomes the trusted snapshot metadata file. If the new snapshot
581            //     metadata file is expired, discard it, abort the update cycle, and report the
582            //     potential freeze attack.
583
584            /////////////////////////////////////////
585            // FIXME(#297): Verify why we don't check expiration here:
586            // Note: this doesn't check the expiration because we need to be able to update it
587            // regardless so we can prevent rollback attacks againsts targets/delegations.
588
589            new_snapshot
590        };
591
592        // FIXME(#297): purging targets is not part of the spec. Do we need to do it?
593        if self
594            .trusted_targets
595            .as_ref()
596            .map(|s| s.version())
597            .unwrap_or(0)
598            != verified
599                .meta()
600                .get(&MetadataPath::targets())
601                .map(|m| m.version())
602                .unwrap_or(0)
603        {
604            self.trusted_targets = None;
605        }
606
607        self.trusted_snapshot = Some(verified);
608
609        // FIXME(#297): purging delegates is not part of the spec. Do we need to do it?
610        self.purge_delegations();
611
612        Ok(true)
613    }
614
615    fn purge_delegations(&mut self) {
616        let purge = {
617            let trusted_snapshot = match self.trusted_snapshot() {
618                Some(s) => s,
619                None => return,
620            };
621            let mut purge = HashSet::new();
622            for (role, trusted_definition) in trusted_snapshot.meta().iter() {
623                let trusted_delegation = match self.trusted_delegations.get(role) {
624                    Some(d) => d,
625                    None => continue,
626                };
627
628                if trusted_delegation.version() > trusted_definition.version() {
629                    let _ = purge.insert(role.clone());
630                    continue;
631                }
632            }
633
634            purge
635        };
636
637        for role in &purge {
638            let _ = self.trusted_delegations.remove(role);
639        }
640    }
641
642    /// Verify and update the targets metadata.
643    pub fn update_targets(
644        &mut self,
645        start_time: &DateTime<Utc>,
646        raw_targets: &RawSignedMetadata<D, TargetsMetadata>,
647    ) -> Result<bool> {
648        let verified = {
649            // FIXME(https://github.com/theupdateframework/specification/issues/113) Checking if
650            // this metadata expired isn't part of the spec. Do we actually want to do this?
651            let trusted_root = self.trusted_root_unexpired(start_time)?;
652            let trusted_targets_version = self.trusted_targets.as_ref().map(|t| t.version());
653
654            self.verify_target_or_delegated_target(
655                start_time,
656                &MetadataPath::targets(),
657                raw_targets,
658                trusted_root.targets().threshold(),
659                trusted_root.targets_keys(),
660                trusted_targets_version,
661            )?
662        };
663
664        if let Some(verified) = verified {
665            self.trusted_targets = Some(verified);
666            Ok(true)
667        } else {
668            Ok(false)
669        }
670    }
671
672    /// Verify and update a delegation metadata.
673    pub fn update_delegated_targets(
674        &mut self,
675        start_time: &DateTime<Utc>,
676        parent_role: &MetadataPath,
677        role: &MetadataPath,
678        raw_delegated_targets: &RawSignedMetadata<D, TargetsMetadata>,
679    ) -> Result<bool> {
680        let verified = {
681            // FIXME(https://github.com/theupdateframework/specification/issues/113) Checking if
682            // this metadata expired isn't part of the spec. Do we actually want to do this?
683            let _ = self.trusted_root_unexpired(start_time)?;
684            let _ = self.trusted_snapshot_unexpired(start_time)?;
685            let trusted_targets = self.trusted_targets_unexpired(start_time)?;
686
687            if trusted_targets.delegations().is_empty() {
688                return Err(Error::UnauthorizedDelegation {
689                    parent_role: parent_role.clone(),
690                    child_role: role.clone(),
691                });
692            };
693
694            let (threshold, keys) = self
695                .find_delegation_threshold_and_keys(parent_role, role)?
696                .ok_or_else(|| Error::UnauthorizedDelegation {
697                    parent_role: parent_role.clone(),
698                    child_role: role.clone(),
699                })?;
700
701            let trusted_delegated_targets_version =
702                self.trusted_delegations.get(role).map(|t| t.version());
703
704            self.verify_target_or_delegated_target(
705                start_time,
706                role,
707                raw_delegated_targets,
708                threshold,
709                keys.into_iter(),
710                trusted_delegated_targets_version,
711            )?
712        };
713
714        if let Some(verified) = verified {
715            let _ = self.trusted_delegations.insert(role.clone(), verified);
716            Ok(true)
717        } else {
718            Ok(false)
719        }
720    }
721
722    fn verify_target_or_delegated_target<'a>(
723        &self,
724        start_time: &DateTime<Utc>,
725        role: &MetadataPath,
726        raw_targets: &RawSignedMetadata<D, TargetsMetadata>,
727        trusted_targets_threshold: u32,
728        trusted_targets_keys: impl Iterator<Item = &'a PublicKey>,
729        trusted_targets_version: Option<u32>,
730    ) -> Result<Option<Verified<TargetsMetadata>>> {
731        // FIXME(https://github.com/theupdateframework/specification/issues/113) Checking if
732        // this metadata expired isn't part of the spec. Do we actually want to do this?
733        let trusted_snapshot = self.trusted_snapshot_unexpired(start_time)?;
734
735        let trusted_targets_description =
736            trusted_snapshot
737                .meta()
738                .get(role)
739                .ok_or_else(|| Error::MissingMetadataDescription {
740                    parent_role: MetadataPath::snapshot(),
741                    child_role: role.clone(),
742                })?;
743
744        /////////////////////////////////////////
745        // TUF-1.0.5 §5.4.1:
746        //
747        //     Check against snapshot metadata. The hashes and version number of the new
748        //     targets metadata file MUST match the hashes (if any) and version number listed
749        //     in the trusted snapshot metadata. This is done, in part, to prevent a
750        //     mix-and-match attack by man-in-the-middle attackers. If the new targets metadata
751        //     file does not match, discard it, abort the update cycle, and report the failure.
752
753        // FIXME: rust-tuf checks the hash during download, but it would be better if we
754        // checked the hash here to make it easier to validate we've correctly implemented the
755        // spec.
756
757        // NOTE(https://github.com/theupdateframework/specification/pull/112): Technically
758        // we're supposed to check the version before checking the signature, but we do it
759        // afterwards. That PR proposes formally moving the version check to after signature
760        // verification.
761
762        /////////////////////////////////////////
763        // TUF-1.0.5 §5.4.2:
764        //
765        //     Check for an arbitrary software attack. The new targets metadata file MUST have
766        //     been signed by a threshold of keys specified in the trusted root metadata file.
767        //     If the new targets metadata file is not signed as required, discard it, abort
768        //     the update cycle, and report the failure.
769
770        let new_targets = verify::verify_signatures(
771            role,
772            raw_targets,
773            trusted_targets_threshold,
774            trusted_targets_keys,
775        )?;
776
777        /////////////////////////////////////////
778        // FIXME(https://github.com/theupdateframework/specification/pull/112): Actually check
779        // the version.
780
781        // FIXME(#295): TUF-1.0.5 §5.3.3.2 says this check should be done when updating the
782        // snapshot, not here.
783        if new_targets.version() != trusted_targets_description.version() {
784            return Err(Error::WrongMetadataVersion {
785                parent_role: MetadataPath::snapshot(),
786                child_role: role.clone(),
787                expected_version: trusted_targets_description.version(),
788                new_version: new_targets.version(),
789            });
790        }
791
792        if let Some(trusted_targets_version) = trusted_targets_version {
793            match new_targets.version().cmp(&trusted_targets_version) {
794                Ordering::Less => {
795                    return Err(Error::AttemptedMetadataRollBack {
796                        role: role.clone(),
797                        trusted_version: trusted_targets_version,
798                        new_version: new_targets.version(),
799                    });
800                }
801                Ordering::Equal => {
802                    return Ok(None);
803                }
804                Ordering::Greater => {}
805            }
806        }
807
808        /////////////////////////////////////////
809        // TUF-1.0.5 §5.4.3:
810        //
811        //     Check for a freeze attack. The latest known time should be lower than the
812        //     expiration timestamp in the new targets metadata file. If so, the new targets
813        //     metadata file becomes the trusted targets metadata file. If the new targets
814        //     metadata file is expired, discard it, abort the update cycle, and report the
815        //     potential freeze attack.
816
817        if new_targets.expires() <= start_time {
818            return Err(Error::ExpiredMetadata {
819                path: role.clone(),
820                expiration: *new_targets.expires(),
821                now: *start_time,
822            });
823        }
824
825        Ok(Some(new_targets))
826    }
827
828    /// Find the signing keys and metadata for the delegation given by `role`, as seen from the
829    /// point of view of `parent_role`.
830    fn find_delegation_threshold_and_keys(
831        &self,
832        parent_role: &MetadataPath,
833        role: &MetadataPath,
834    ) -> Result<Option<(u32, Vec<&PublicKey>)>> {
835        // Find the parent TargetsMetadata that is expected to refer to `role`.
836        let trusted_parent = if parent_role == &MetadataPath::targets() {
837            if let Some(trusted_targets) = self.trusted_targets() {
838                trusted_targets
839            } else {
840                return Err(Error::MetadataNotFound {
841                    path: parent_role.clone(),
842                    version: MetadataVersion::None,
843                });
844            }
845        } else if let Some(trusted_parent) = self.trusted_delegations.get(parent_role) {
846            trusted_parent
847        } else {
848            return Err(Error::MetadataNotFound {
849                path: parent_role.clone(),
850                version: MetadataVersion::None,
851            });
852        };
853
854        // Only consider targets metadata that define delegations.
855        let trusted_delegations = trusted_parent.delegations();
856
857        for trusted_delegation in trusted_delegations.roles() {
858            if trusted_delegation.name() != role {
859                continue;
860            }
861
862            // Filter the delegations keys to just the ones for this delegation.
863            let authorized_keys = trusted_delegations
864                .keys()
865                .iter()
866                .filter_map(|(k, v)| {
867                    if trusted_delegation.key_ids().contains(k) {
868                        Some(v)
869                    } else {
870                        None
871                    }
872                })
873                .collect();
874
875            return Ok(Some((trusted_delegation.threshold(), authorized_keys)));
876        }
877
878        Ok(None)
879    }
880
881    /// Get a reference to the description needed to verify the target defined by the given
882    /// `TargetPath`. Returns an `Error` if the target is not defined in the trusted
883    /// metadata. This may mean the target exists somewhere in the metadata, but the chain of trust
884    /// to that target may be invalid or incomplete.
885    pub fn target_description(&self, target_path: &TargetPath) -> Result<TargetDescription> {
886        self.target_description_with_start_time(&Utc::now(), target_path)
887    }
888
889    /// Get a reference to the description needed to verify the target defined by the given
890    /// `TargetPath`. Returns an `Error` if the target is not defined in the trusted
891    /// metadata. This may mean the target exists somewhere in the metadata, but the chain of trust
892    /// to that target may be invalid or incomplete.
893    pub fn target_description_with_start_time(
894        &self,
895        start_time: &DateTime<Utc>,
896        target_path: &TargetPath,
897    ) -> Result<TargetDescription> {
898        let _ = self.trusted_root_unexpired(start_time)?;
899        let _ = self.trusted_snapshot_unexpired(start_time)?;
900        let targets = self.trusted_targets_unexpired(start_time)?;
901
902        if let Some(d) = targets.targets().get(target_path) {
903            return Ok(d.clone());
904        }
905
906        fn lookup<'a, D: Pouf>(
907            start_time: &DateTime<Utc>,
908            tuf: &'a Database<D>,
909            default_terminate: bool,
910            current_depth: u32,
911            target_path: &TargetPath,
912            delegations: &'a Delegations,
913            parents: &[HashSet<TargetPath>],
914            visited: &mut HashSet<&'a MetadataPath>,
915        ) -> (bool, Option<TargetDescription>) {
916            for delegation in delegations.roles() {
917                if visited.contains(delegation.name()) {
918                    return (delegation.terminating(), None);
919                }
920                let _ = visited.insert(delegation.name());
921
922                let mut new_parents = parents.to_owned();
923                new_parents.push(delegation.paths().clone());
924
925                if current_depth > 0 && !target_path.matches_chain(parents) {
926                    return (delegation.terminating(), None);
927                }
928
929                let trusted_delegation = match tuf.trusted_delegations.get(delegation.name()) {
930                    Some(trusted_delegation) => trusted_delegation,
931                    None => return (delegation.terminating(), None),
932                };
933
934                if trusted_delegation.expires() <= start_time {
935                    return (delegation.terminating(), None);
936                }
937
938                if let Some(target) = trusted_delegation.targets().get(target_path) {
939                    return (delegation.terminating(), Some(target.clone()));
940                }
941
942                let trusted_child_delegations = trusted_delegation.delegations();
943
944                // We only need to check the child delegations if it delegates to any child roles.
945                if !trusted_child_delegations.roles().is_empty() {
946                    let mut new_parents = parents.to_vec();
947                    new_parents.push(delegation.paths().clone());
948                    let (term, res) = lookup(
949                        start_time,
950                        tuf,
951                        delegation.terminating(),
952                        current_depth + 1,
953                        target_path,
954                        trusted_child_delegations,
955                        &new_parents,
956                        visited,
957                    );
958                    if term {
959                        return (true, res);
960                    } else if res.is_some() {
961                        return (term, res);
962                    }
963                }
964            }
965            (default_terminate, None)
966        }
967
968        let delegations = targets.delegations();
969        if delegations.roles().is_empty() {
970            Err(Error::TargetNotFound(target_path.clone()))
971        } else {
972            let mut visited = HashSet::new();
973            lookup(
974                start_time,
975                self,
976                false,
977                0,
978                target_path,
979                delegations,
980                &[],
981                &mut visited,
982            )
983            .1
984            .ok_or_else(|| Error::TargetNotFound(target_path.clone()))
985        }
986    }
987
988    fn purge_metadata(&mut self) {
989        self.trusted_snapshot = None;
990        self.trusted_targets = None;
991        self.trusted_timestamp = None;
992        self.trusted_delegations.clear();
993    }
994
995    fn trusted_root_unexpired(&self, start_time: &DateTime<Utc>) -> Result<&RootMetadata> {
996        let trusted_root = &self.trusted_root;
997        if trusted_root.expires() <= start_time {
998            return Err(Error::ExpiredMetadata {
999                path: MetadataPath::root(),
1000                expiration: *trusted_root.expires(),
1001                now: *start_time,
1002            });
1003        }
1004        Ok(trusted_root)
1005    }
1006
1007    fn trusted_timestamp_unexpired(
1008        &self,
1009        start_time: &DateTime<Utc>,
1010    ) -> Result<&TimestampMetadata> {
1011        match self.trusted_timestamp {
1012            Some(ref trusted_timestamp) => {
1013                if trusted_timestamp.expires() <= start_time {
1014                    return Err(Error::ExpiredMetadata {
1015                        path: MetadataPath::timestamp(),
1016                        expiration: *trusted_timestamp.expires(),
1017                        now: *start_time,
1018                    });
1019                }
1020                Ok(trusted_timestamp)
1021            }
1022            None => Err(Error::MetadataNotFound {
1023                path: MetadataPath::timestamp(),
1024                version: MetadataVersion::None,
1025            }),
1026        }
1027    }
1028
1029    fn trusted_snapshot_unexpired(&self, start_time: &DateTime<Utc>) -> Result<&SnapshotMetadata> {
1030        match self.trusted_snapshot {
1031            Some(ref trusted_snapshot) => {
1032                if trusted_snapshot.expires() <= start_time {
1033                    return Err(Error::ExpiredMetadata {
1034                        path: MetadataPath::snapshot(),
1035                        expiration: *trusted_snapshot.expires(),
1036                        now: *start_time,
1037                    });
1038                }
1039                Ok(trusted_snapshot)
1040            }
1041            None => Err(Error::MetadataNotFound {
1042                path: MetadataPath::snapshot(),
1043                version: MetadataVersion::None,
1044            }),
1045        }
1046    }
1047
1048    fn trusted_targets_unexpired(&self, start_time: &DateTime<Utc>) -> Result<&TargetsMetadata> {
1049        match self.trusted_targets {
1050            Some(ref trusted_targets) => {
1051                if trusted_targets.expires() <= start_time {
1052                    return Err(Error::ExpiredMetadata {
1053                        path: MetadataPath::targets(),
1054                        expiration: *trusted_targets.expires(),
1055                        now: *start_time,
1056                    });
1057                }
1058                Ok(trusted_targets)
1059            }
1060            None => Err(Error::MetadataNotFound {
1061                path: MetadataPath::targets(),
1062                version: MetadataVersion::None,
1063            }),
1064        }
1065    }
1066}
1067
1068impl<D: Pouf> Clone for Database<D> {
1069    fn clone(&self) -> Self {
1070        Self {
1071            trusted_root: self.trusted_root.clone(),
1072            trusted_targets: self.trusted_targets.clone(),
1073            trusted_snapshot: self.trusted_snapshot.clone(),
1074            trusted_timestamp: self.trusted_timestamp.clone(),
1075            trusted_delegations: self.trusted_delegations.clone(),
1076            pouf: PhantomData,
1077        }
1078    }
1079}
1080
1081#[cfg(test)]
1082mod test {
1083    use super::*;
1084    use crate::crypto::{Ed25519PrivateKey, HashAlgorithm, PrivateKey};
1085    use crate::metadata::{
1086        RawSignedMetadataSetBuilder, RootMetadataBuilder, SnapshotMetadataBuilder,
1087        TargetsMetadataBuilder, TimestampMetadataBuilder,
1088    };
1089    use crate::pouf::Pouf1;
1090    use assert_matches::assert_matches;
1091    use std::iter::once;
1092    use std::sync::LazyLock;
1093
1094    static KEYS: LazyLock<Vec<Ed25519PrivateKey>> = LazyLock::new(|| {
1095        let keys: &[&[u8]] = &[
1096            include_bytes!("../tests/ed25519/ed25519-1.pk8.der"),
1097            include_bytes!("../tests/ed25519/ed25519-2.pk8.der"),
1098            include_bytes!("../tests/ed25519/ed25519-3.pk8.der"),
1099            include_bytes!("../tests/ed25519/ed25519-4.pk8.der"),
1100            include_bytes!("../tests/ed25519/ed25519-5.pk8.der"),
1101            include_bytes!("../tests/ed25519/ed25519-6.pk8.der"),
1102        ];
1103        keys.iter()
1104            .map(|b| Ed25519PrivateKey::from_pkcs8(b).unwrap())
1105            .collect()
1106    });
1107
1108    #[test]
1109    fn root_trusted_keys_success() {
1110        let root = RootMetadataBuilder::new()
1111            .root_key(KEYS[0].public().clone())
1112            .snapshot_key(KEYS[0].public().clone())
1113            .targets_key(KEYS[0].public().clone())
1114            .timestamp_key(KEYS[0].public().clone())
1115            .signed::<Pouf1>(&KEYS[0])
1116            .unwrap();
1117        let raw_root = root.to_raw().unwrap();
1118
1119        assert_matches!(
1120            Database::from_root_with_trusted_keys(&raw_root, 1, once(KEYS[0].public())),
1121            Ok(_)
1122        );
1123    }
1124
1125    #[test]
1126    fn root_trusted_keys_failure() {
1127        let root = RootMetadataBuilder::new()
1128            .root_key(KEYS[0].public().clone())
1129            .snapshot_key(KEYS[0].public().clone())
1130            .targets_key(KEYS[0].public().clone())
1131            .timestamp_key(KEYS[0].public().clone())
1132            .signed::<Pouf1>(&KEYS[0])
1133            .unwrap();
1134        let raw_root = root.to_raw().unwrap();
1135
1136        assert_matches!(
1137            Database::from_root_with_trusted_keys(&raw_root, 1, once(KEYS[1].public())),
1138            Err(Error::MetadataMissingSignatures {
1139                role,
1140                number_of_valid_signatures: 0,
1141                threshold: 1,
1142            })
1143            if role == MetadataPath::root()
1144        );
1145    }
1146
1147    #[test]
1148    fn from_trusted_metadata_success() {
1149        let root = RootMetadataBuilder::new()
1150            .root_key(KEYS[0].public().clone())
1151            .snapshot_key(KEYS[0].public().clone())
1152            .targets_key(KEYS[0].public().clone())
1153            .timestamp_key(KEYS[0].public().clone())
1154            .signed::<Pouf1>(&KEYS[0])
1155            .unwrap()
1156            .to_raw()
1157            .unwrap();
1158
1159        let metadata = RawSignedMetadataSetBuilder::new().root(root).build();
1160
1161        assert_matches!(Database::from_trusted_metadata(&metadata), Ok(_));
1162    }
1163
1164    #[test]
1165    fn from_trusted_metadata_failure() {
1166        let root = RootMetadataBuilder::new()
1167            .root_key(KEYS[0].public().clone())
1168            .snapshot_key(KEYS[0].public().clone())
1169            .targets_key(KEYS[0].public().clone())
1170            .timestamp_key(KEYS[0].public().clone())
1171            .signed::<Pouf1>(&KEYS[1])
1172            .unwrap()
1173            .to_raw()
1174            .unwrap();
1175
1176        let metadata = RawSignedMetadataSetBuilder::new().root(root).build();
1177
1178        assert_matches!(
1179            Database::from_trusted_metadata(&metadata),
1180            Err(Error::MetadataMissingSignatures {
1181                role,
1182                number_of_valid_signatures: 0,
1183                threshold: 1,
1184            })
1185            if role == MetadataPath::root()
1186        );
1187    }
1188
1189    #[test]
1190    fn from_metadata_with_trusted_keys_success() {
1191        let root = RootMetadataBuilder::new()
1192            .root_key(KEYS[0].public().clone())
1193            .snapshot_key(KEYS[0].public().clone())
1194            .targets_key(KEYS[0].public().clone())
1195            .timestamp_key(KEYS[0].public().clone())
1196            .signed::<Pouf1>(&KEYS[0])
1197            .unwrap()
1198            .to_raw()
1199            .unwrap();
1200
1201        let metadata = RawSignedMetadataSetBuilder::new().root(root).build();
1202
1203        assert_matches!(
1204            Database::from_metadata_with_trusted_keys(&metadata, 1, once(KEYS[0].public())),
1205            Ok(_)
1206        );
1207    }
1208
1209    #[test]
1210    fn from_metadata_with_trusted_keys_failure() {
1211        let root = RootMetadataBuilder::new()
1212            .root_key(KEYS[0].public().clone())
1213            .snapshot_key(KEYS[0].public().clone())
1214            .targets_key(KEYS[0].public().clone())
1215            .timestamp_key(KEYS[0].public().clone())
1216            .signed::<Pouf1>(&KEYS[0])
1217            .unwrap()
1218            .to_raw()
1219            .unwrap();
1220
1221        let metadata = RawSignedMetadataSetBuilder::new().root(root).build();
1222
1223        assert_matches!(
1224            Database::from_metadata_with_trusted_keys(&metadata, 1, once(KEYS[1].public())),
1225            Err(Error::MetadataMissingSignatures {
1226                role,
1227                number_of_valid_signatures: 0,
1228                threshold: 1,
1229            })
1230            if role == MetadataPath::root()
1231        );
1232    }
1233
1234    #[test]
1235    fn good_root_rotation() {
1236        let raw_root = RootMetadataBuilder::new()
1237            .root_key(KEYS[0].public().clone())
1238            .snapshot_key(KEYS[0].public().clone())
1239            .targets_key(KEYS[0].public().clone())
1240            .timestamp_key(KEYS[0].public().clone())
1241            .signed::<Pouf1>(&KEYS[0])
1242            .unwrap()
1243            .to_raw()
1244            .unwrap();
1245
1246        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1247
1248        let mut root = RootMetadataBuilder::new()
1249            .version(2)
1250            .root_key(KEYS[1].public().clone())
1251            .snapshot_key(KEYS[1].public().clone())
1252            .targets_key(KEYS[1].public().clone())
1253            .timestamp_key(KEYS[1].public().clone())
1254            .signed::<Pouf1>(&KEYS[1])
1255            .unwrap();
1256
1257        // add the original key's signature to make it cross signed
1258        root.add_signature(&KEYS[0]).unwrap();
1259        let raw_root = root.to_raw().unwrap();
1260
1261        assert_matches!(tuf.update_root(&raw_root), Ok(()));
1262
1263        // second update with the same metadata should fail.
1264        assert_matches!(
1265            tuf.update_root(&raw_root),
1266            Err(Error::AttemptedMetadataRollBack { role, trusted_version: 2, new_version: 2 })
1267            if role == MetadataPath::root()
1268        );
1269    }
1270
1271    #[test]
1272    fn no_cross_sign_root_rotation() {
1273        let raw_root = RootMetadataBuilder::new()
1274            .root_key(KEYS[0].public().clone())
1275            .snapshot_key(KEYS[0].public().clone())
1276            .targets_key(KEYS[0].public().clone())
1277            .timestamp_key(KEYS[0].public().clone())
1278            .signed::<Pouf1>(&KEYS[0])
1279            .unwrap()
1280            .to_raw()
1281            .unwrap();
1282
1283        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1284
1285        let raw_root = RootMetadataBuilder::new()
1286            .root_key(KEYS[1].public().clone())
1287            .snapshot_key(KEYS[1].public().clone())
1288            .targets_key(KEYS[1].public().clone())
1289            .timestamp_key(KEYS[1].public().clone())
1290            .signed::<Pouf1>(&KEYS[1])
1291            .unwrap()
1292            .to_raw()
1293            .unwrap();
1294
1295        assert!(tuf.update_root(&raw_root).is_err());
1296    }
1297
1298    #[test]
1299    fn good_timestamp_update() {
1300        let now = Utc::now();
1301
1302        let raw_root = RootMetadataBuilder::new()
1303            .root_key(KEYS[0].public().clone())
1304            .snapshot_key(KEYS[1].public().clone())
1305            .targets_key(KEYS[1].public().clone())
1306            .timestamp_key(KEYS[1].public().clone())
1307            .signed::<Pouf1>(&KEYS[0])
1308            .unwrap()
1309            .to_raw()
1310            .unwrap();
1311
1312        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1313
1314        let snapshot = SnapshotMetadataBuilder::new()
1315            .signed::<Pouf1>(&KEYS[1])
1316            .unwrap();
1317
1318        let timestamp =
1319            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1320                .unwrap()
1321                .signed::<Pouf1>(&KEYS[1])
1322                .unwrap();
1323        let raw_timestamp = timestamp.to_raw().unwrap();
1324
1325        assert_matches!(
1326            tuf.update_timestamp(&now, &raw_timestamp),
1327            Ok(Some(_parsed_timestamp))
1328        );
1329
1330        // second update should do nothing
1331        assert_matches!(tuf.update_timestamp(&now, &raw_timestamp), Ok(None))
1332    }
1333
1334    #[test]
1335    fn bad_timestamp_update_wrong_key() {
1336        let now = Utc::now();
1337
1338        let raw_root = RootMetadataBuilder::new()
1339            .root_key(KEYS[0].public().clone())
1340            .snapshot_key(KEYS[1].public().clone())
1341            .targets_key(KEYS[1].public().clone())
1342            .timestamp_key(KEYS[1].public().clone())
1343            .signed::<Pouf1>(&KEYS[0])
1344            .unwrap()
1345            .to_raw()
1346            .unwrap();
1347
1348        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1349
1350        let snapshot = SnapshotMetadataBuilder::new()
1351            .signed::<Pouf1>(&KEYS[1])
1352            .unwrap();
1353
1354        let raw_timestamp =
1355            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1356                .unwrap()
1357                // sign it with the root key
1358                .signed::<Pouf1>(&KEYS[0])
1359                .unwrap()
1360                .to_raw()
1361                .unwrap();
1362
1363        assert!(tuf.update_timestamp(&now, &raw_timestamp).is_err())
1364    }
1365
1366    #[test]
1367    fn good_snapshot_update() {
1368        let now = Utc::now();
1369
1370        let raw_root = RootMetadataBuilder::new()
1371            .root_key(KEYS[0].public().clone())
1372            .snapshot_key(KEYS[1].public().clone())
1373            .targets_key(KEYS[2].public().clone())
1374            .timestamp_key(KEYS[2].public().clone())
1375            .signed::<Pouf1>(&KEYS[0])
1376            .unwrap()
1377            .to_raw()
1378            .unwrap();
1379
1380        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1381
1382        let snapshot = SnapshotMetadataBuilder::new().signed(&KEYS[1]).unwrap();
1383        let raw_snapshot = snapshot.to_raw().unwrap();
1384
1385        let raw_timestamp =
1386            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1387                .unwrap()
1388                .signed::<Pouf1>(&KEYS[2])
1389                .unwrap()
1390                .to_raw()
1391                .unwrap();
1392
1393        tuf.update_timestamp(&now, &raw_timestamp).unwrap();
1394
1395        assert_matches!(tuf.update_snapshot(&now, &raw_snapshot), Ok(true));
1396
1397        // second update should do nothing
1398        assert_matches!(tuf.update_snapshot(&now, &raw_snapshot), Ok(false));
1399    }
1400
1401    #[test]
1402    fn bad_snapshot_update_wrong_key() {
1403        let now = Utc::now();
1404
1405        let raw_root = RootMetadataBuilder::new()
1406            .root_key(KEYS[0].public().clone())
1407            .snapshot_key(KEYS[1].public().clone())
1408            .targets_key(KEYS[2].public().clone())
1409            .timestamp_key(KEYS[2].public().clone())
1410            .signed::<Pouf1>(&KEYS[0])
1411            .unwrap()
1412            .to_raw()
1413            .unwrap();
1414
1415        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1416
1417        let snapshot = SnapshotMetadataBuilder::new()
1418            .signed::<Pouf1>(&KEYS[2])
1419            .unwrap();
1420        let raw_snapshot = snapshot.to_raw().unwrap();
1421
1422        let raw_timestamp =
1423            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1424                .unwrap()
1425                // sign it with the targets key
1426                .signed::<Pouf1>(&KEYS[2])
1427                .unwrap()
1428                .to_raw()
1429                .unwrap();
1430
1431        tuf.update_timestamp(&now, &raw_timestamp).unwrap();
1432
1433        assert!(tuf.update_snapshot(&now, &raw_snapshot).is_err());
1434    }
1435
1436    #[test]
1437    fn bad_snapshot_update_wrong_version() {
1438        let now = Utc::now();
1439
1440        let raw_root = RootMetadataBuilder::new()
1441            .root_key(KEYS[0].public().clone())
1442            .snapshot_key(KEYS[1].public().clone())
1443            .targets_key(KEYS[2].public().clone())
1444            .timestamp_key(KEYS[2].public().clone())
1445            .signed::<Pouf1>(&KEYS[0])
1446            .unwrap()
1447            .to_raw()
1448            .unwrap();
1449
1450        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1451
1452        let snapshot = SnapshotMetadataBuilder::new()
1453            .version(2)
1454            .signed::<Pouf1>(&KEYS[2])
1455            .unwrap();
1456
1457        let raw_timestamp =
1458            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1459                .unwrap()
1460                .signed::<Pouf1>(&KEYS[2])
1461                .unwrap()
1462                .to_raw()
1463                .unwrap();
1464
1465        tuf.update_timestamp(&now, &raw_timestamp).unwrap();
1466
1467        let raw_snapshot = SnapshotMetadataBuilder::new()
1468            .version(1)
1469            .signed::<Pouf1>(&KEYS[1])
1470            .unwrap()
1471            .to_raw()
1472            .unwrap();
1473
1474        assert!(tuf.update_snapshot(&now, &raw_snapshot).is_err());
1475    }
1476
1477    #[test]
1478    fn good_targets_update() {
1479        let now = Utc::now();
1480
1481        let raw_root = RootMetadataBuilder::new()
1482            .root_key(KEYS[0].public().clone())
1483            .snapshot_key(KEYS[1].public().clone())
1484            .targets_key(KEYS[2].public().clone())
1485            .timestamp_key(KEYS[3].public().clone())
1486            .signed::<Pouf1>(&KEYS[0])
1487            .unwrap()
1488            .to_raw()
1489            .unwrap();
1490
1491        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1492
1493        let signed_targets = TargetsMetadataBuilder::new()
1494            .signed::<Pouf1>(&KEYS[2])
1495            .unwrap();
1496        let raw_targets = signed_targets.to_raw().unwrap();
1497
1498        let snapshot = SnapshotMetadataBuilder::new()
1499            .insert_metadata(&signed_targets, &[HashAlgorithm::Sha256])
1500            .unwrap()
1501            .signed::<Pouf1>(&KEYS[1])
1502            .unwrap();
1503        let raw_snapshot = snapshot.to_raw().unwrap();
1504
1505        let raw_timestamp =
1506            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1507                .unwrap()
1508                .signed::<Pouf1>(&KEYS[3])
1509                .unwrap()
1510                .to_raw()
1511                .unwrap();
1512
1513        tuf.update_timestamp(&now, &raw_timestamp).unwrap();
1514        tuf.update_snapshot(&now, &raw_snapshot).unwrap();
1515
1516        assert_matches!(tuf.update_targets(&now, &raw_targets), Ok(true));
1517
1518        // second update should do nothing
1519        assert_matches!(tuf.update_targets(&now, &raw_targets), Ok(false));
1520    }
1521
1522    #[test]
1523    fn bad_targets_update_wrong_key() {
1524        let now = Utc::now();
1525
1526        let raw_root = RootMetadataBuilder::new()
1527            .root_key(KEYS[0].public().clone())
1528            .snapshot_key(KEYS[1].public().clone())
1529            .targets_key(KEYS[2].public().clone())
1530            .timestamp_key(KEYS[3].public().clone())
1531            .signed::<Pouf1>(&KEYS[0])
1532            .unwrap()
1533            .to_raw()
1534            .unwrap();
1535
1536        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1537
1538        let signed_targets = TargetsMetadataBuilder::new()
1539            // sign it with the timestamp key
1540            .signed::<Pouf1>(&KEYS[3])
1541            .unwrap();
1542        let raw_targets = signed_targets.to_raw().unwrap();
1543
1544        let snapshot = SnapshotMetadataBuilder::new()
1545            .insert_metadata(&signed_targets, &[HashAlgorithm::Sha256])
1546            .unwrap()
1547            .signed::<Pouf1>(&KEYS[1])
1548            .unwrap();
1549        let raw_snapshot = snapshot.to_raw().unwrap();
1550
1551        let raw_timestamp =
1552            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1553                .unwrap()
1554                .signed::<Pouf1>(&KEYS[3])
1555                .unwrap()
1556                .to_raw()
1557                .unwrap();
1558
1559        tuf.update_timestamp(&now, &raw_timestamp).unwrap();
1560        tuf.update_snapshot(&now, &raw_snapshot).unwrap();
1561
1562        assert!(tuf.update_targets(&now, &raw_targets).is_err());
1563    }
1564
1565    #[test]
1566    fn bad_targets_update_wrong_version() {
1567        let now = Utc::now();
1568
1569        let raw_root = RootMetadataBuilder::new()
1570            .root_key(KEYS[0].public().clone())
1571            .snapshot_key(KEYS[1].public().clone())
1572            .targets_key(KEYS[2].public().clone())
1573            .timestamp_key(KEYS[3].public().clone())
1574            .signed::<Pouf1>(&KEYS[0])
1575            .unwrap()
1576            .to_raw()
1577            .unwrap();
1578
1579        let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1580
1581        let signed_targets = TargetsMetadataBuilder::new()
1582            .version(2)
1583            .signed::<Pouf1>(&KEYS[2])
1584            .unwrap();
1585
1586        let snapshot = SnapshotMetadataBuilder::new()
1587            .insert_metadata(&signed_targets, &[HashAlgorithm::Sha256])
1588            .unwrap()
1589            .signed::<Pouf1>(&KEYS[1])
1590            .unwrap();
1591        let raw_snapshot = snapshot.to_raw().unwrap();
1592
1593        let raw_timestamp =
1594            TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
1595                .unwrap()
1596                .signed::<Pouf1>(&KEYS[3])
1597                .unwrap()
1598                .to_raw()
1599                .unwrap();
1600
1601        tuf.update_timestamp(&now, &raw_timestamp).unwrap();
1602        tuf.update_snapshot(&now, &raw_snapshot).unwrap();
1603
1604        let raw_targets = TargetsMetadataBuilder::new()
1605            .version(1)
1606            .signed::<Pouf1>(&KEYS[2])
1607            .unwrap()
1608            .to_raw()
1609            .unwrap();
1610
1611        assert!(tuf.update_targets(&now, &raw_targets).is_err());
1612    }
1613
1614    #[test]
1615    fn test_update_metadata_succeeds_with_good_metadata() {
1616        let raw_root1 = RootMetadataBuilder::new()
1617            .root_key(KEYS[0].public().clone())
1618            .targets_key(KEYS[1].public().clone())
1619            .snapshot_key(KEYS[2].public().clone())
1620            .timestamp_key(KEYS[3].public().clone())
1621            .signed::<Pouf1>(&KEYS[0])
1622            .unwrap()
1623            .to_raw()
1624            .unwrap();
1625
1626        let signed_targets1 = TargetsMetadataBuilder::new()
1627            .signed::<Pouf1>(&KEYS[1])
1628            .unwrap();
1629        let raw_targets1 = signed_targets1.to_raw().unwrap();
1630
1631        let snapshot1 = SnapshotMetadataBuilder::new()
1632            .insert_metadata(&signed_targets1, &[HashAlgorithm::Sha256])
1633            .unwrap()
1634            .signed::<Pouf1>(&KEYS[2])
1635            .unwrap();
1636        let raw_snapshot1 = snapshot1.to_raw().unwrap();
1637
1638        let raw_timestamp1 =
1639            TimestampMetadataBuilder::from_snapshot(&snapshot1, &[HashAlgorithm::Sha256])
1640                .unwrap()
1641                .signed::<Pouf1>(&KEYS[3])
1642                .unwrap()
1643                .to_raw()
1644                .unwrap();
1645
1646        let metadata1 = RawSignedMetadataSetBuilder::new()
1647            .root(raw_root1)
1648            .targets(raw_targets1)
1649            .snapshot(raw_snapshot1)
1650            .timestamp(raw_timestamp1)
1651            .build();
1652
1653        let mut tuf = Database::from_trusted_metadata(&metadata1).unwrap();
1654
1655        let raw_root2 = RootMetadataBuilder::new()
1656            .version(2)
1657            .root_key(KEYS[0].public().clone())
1658            .targets_key(KEYS[1].public().clone())
1659            .snapshot_key(KEYS[2].public().clone())
1660            .timestamp_key(KEYS[3].public().clone())
1661            .signed::<Pouf1>(&KEYS[0])
1662            .unwrap()
1663            .to_raw()
1664            .unwrap();
1665
1666        let signed_targets2 = TargetsMetadataBuilder::new()
1667            .version(2)
1668            .signed::<Pouf1>(&KEYS[1])
1669            .unwrap();
1670        let raw_targets2 = signed_targets2.to_raw().unwrap();
1671
1672        let snapshot2 = SnapshotMetadataBuilder::new()
1673            .version(2)
1674            .insert_metadata(&signed_targets2, &[HashAlgorithm::Sha256])
1675            .unwrap()
1676            .signed::<Pouf1>(&KEYS[2])
1677            .unwrap();
1678        let raw_snapshot2 = snapshot2.to_raw().unwrap();
1679
1680        let raw_timestamp2 =
1681            TimestampMetadataBuilder::from_snapshot(&snapshot2, &[HashAlgorithm::Sha256])
1682                .unwrap()
1683                .version(2)
1684                .signed::<Pouf1>(&KEYS[3])
1685                .unwrap()
1686                .to_raw()
1687                .unwrap();
1688
1689        let metadata2 = RawSignedMetadataSetBuilder::new()
1690            .root(raw_root2)
1691            .targets(raw_targets2)
1692            .snapshot(raw_snapshot2)
1693            .timestamp(raw_timestamp2)
1694            .build();
1695
1696        assert_matches!(tuf.update_metadata(&metadata2), Ok(true));
1697    }
1698
1699    #[test]
1700    fn test_update_metadata_fails_with_bad_metadata() {
1701        let raw_root1 = RootMetadataBuilder::new()
1702            .root_key(KEYS[0].public().clone())
1703            .targets_key(KEYS[1].public().clone())
1704            .snapshot_key(KEYS[2].public().clone())
1705            .timestamp_key(KEYS[3].public().clone())
1706            .signed::<Pouf1>(&KEYS[0])
1707            .unwrap()
1708            .to_raw()
1709            .unwrap();
1710
1711        let signed_targets1 = TargetsMetadataBuilder::new()
1712            .signed::<Pouf1>(&KEYS[1])
1713            .unwrap();
1714        let raw_targets1 = signed_targets1.to_raw().unwrap();
1715
1716        let snapshot1 = SnapshotMetadataBuilder::new()
1717            .insert_metadata(&signed_targets1, &[HashAlgorithm::Sha256])
1718            .unwrap()
1719            .signed::<Pouf1>(&KEYS[2])
1720            .unwrap();
1721        let raw_snapshot1 = snapshot1.to_raw().unwrap();
1722
1723        let raw_timestamp1 =
1724            TimestampMetadataBuilder::from_snapshot(&snapshot1, &[HashAlgorithm::Sha256])
1725                .unwrap()
1726                .signed::<Pouf1>(&KEYS[3])
1727                .unwrap()
1728                .to_raw()
1729                .unwrap();
1730
1731        let metadata1 = RawSignedMetadataSetBuilder::new()
1732            .root(raw_root1)
1733            .targets(raw_targets1)
1734            .snapshot(raw_snapshot1)
1735            .timestamp(raw_timestamp1)
1736            .build();
1737
1738        let mut tuf = Database::from_trusted_metadata(&metadata1).unwrap();
1739
1740        let raw_root2 = RootMetadataBuilder::new()
1741            .version(2)
1742            .root_key(KEYS[1].public().clone())
1743            .targets_key(KEYS[2].public().clone())
1744            .snapshot_key(KEYS[3].public().clone())
1745            .timestamp_key(KEYS[4].public().clone())
1746            .signed::<Pouf1>(&KEYS[1])
1747            .unwrap()
1748            .to_raw()
1749            .unwrap();
1750
1751        let signed_targets2 = TargetsMetadataBuilder::new()
1752            .version(2)
1753            .signed::<Pouf1>(&KEYS[1])
1754            .unwrap();
1755        let raw_targets2 = signed_targets2.to_raw().unwrap();
1756
1757        let snapshot2 = SnapshotMetadataBuilder::new()
1758            .version(2)
1759            .insert_metadata(&signed_targets2, &[HashAlgorithm::Sha256])
1760            .unwrap()
1761            .signed::<Pouf1>(&KEYS[2])
1762            .unwrap();
1763        let raw_snapshot2 = snapshot2.to_raw().unwrap();
1764
1765        let raw_timestamp2 =
1766            TimestampMetadataBuilder::from_snapshot(&snapshot2, &[HashAlgorithm::Sha256])
1767                .unwrap()
1768                .version(2)
1769                .signed::<Pouf1>(&KEYS[3])
1770                .unwrap()
1771                .to_raw()
1772                .unwrap();
1773
1774        let metadata2 = RawSignedMetadataSetBuilder::new()
1775            .root(raw_root2)
1776            .targets(raw_targets2)
1777            .snapshot(raw_snapshot2)
1778            .timestamp(raw_timestamp2)
1779            .build();
1780
1781        assert_matches!(
1782            tuf.update_metadata(&metadata2),
1783            Err(Error::MetadataMissingSignatures {
1784                role,
1785                number_of_valid_signatures: 0,
1786                threshold: 1,
1787            })
1788            if role == MetadataPath::root()
1789        );
1790    }
1791}