Skip to main content

tuf/
metadata.rs

1//! TUF metadata.
2
3use chrono::offset::Utc;
4use chrono::{DateTime, Duration};
5use futures_io::AsyncRead;
6use serde::{
7    de::DeserializeOwned, de::Error as DeserializeError, ser::Error as SerializeError, Deserialize,
8    Deserializer, Serialize, Serializer,
9};
10use std::borrow::{Borrow, Cow};
11use std::collections::{HashMap, HashSet};
12use std::fmt::{self, Debug, Display};
13use std::marker::PhantomData;
14use std::str;
15
16use crate::crypto::{self, HashAlgorithm, HashValue, KeyId, PrivateKey, PublicKey, Signature};
17use crate::error::Error;
18use crate::pouf::pouf1::shims;
19use crate::pouf::Pouf;
20use crate::Result;
21
22#[rustfmt::skip]
23static PATH_ILLEGAL_COMPONENTS: &[&str] = &[
24    ".", // current dir
25    "..", // parent dir
26         // TODO ? "0", // may translate to nul in windows
27];
28
29#[rustfmt::skip]
30static PATH_ILLEGAL_COMPONENTS_CASE_INSENSITIVE: &[&str] = &[
31    // DOS device files
32    "CON",
33    "PRN",
34    "AUX",
35    "NUL",
36    "COM1",
37    "COM2",
38    "COM3",
39    "COM4",
40    "COM5",
41    "COM6",
42    "COM7",
43    "COM8",
44    "COM9",
45    "LPT1",
46    "LPT2",
47    "LPT3",
48    "LPT4",
49    "LPT5",
50    "LPT6",
51    "LPT7",
52    "LPT8",
53    "LPT9",
54    "KEYBD$",
55    "CLOCK$",
56    "SCREEN$",
57    "$IDLE$",
58    "CONFIG$",
59];
60
61#[rustfmt::skip]
62static PATH_ILLEGAL_STRINGS: &[&str] = &[
63    ":", // for *nix compatibility
64    "\\", // for windows compatibility
65    "<",
66    ">",
67    "\"",
68    "|",
69    "?",
70    // control characters, all illegal in FAT
71    "\u{000}",
72    "\u{001}",
73    "\u{002}",
74    "\u{003}",
75    "\u{004}",
76    "\u{005}",
77    "\u{006}",
78    "\u{007}",
79    "\u{008}",
80    "\u{009}",
81    "\u{00a}",
82    "\u{00b}",
83    "\u{00c}",
84    "\u{00d}",
85    "\u{00e}",
86    "\u{00f}",
87    "\u{010}",
88    "\u{011}",
89    "\u{012}",
90    "\u{013}",
91    "\u{014}",
92    "\u{015}",
93    "\u{016}",
94    "\u{017}",
95    "\u{018}",
96    "\u{019}",
97    "\u{01a}",
98    "\u{01b}",
99    "\u{01c}",
100    "\u{01d}",
101    "\u{01e}",
102    "\u{01f}",
103    "\u{07f}",
104];
105
106fn safe_path(path: &str) -> Result<()> {
107    if path.is_empty() {
108        return Err(Error::IllegalArgument("Path cannot be empty".into()));
109    }
110
111    if path.starts_with('/') {
112        return Err(Error::IllegalArgument("Cannot start with '/'".into()));
113    }
114
115    for bad_str in PATH_ILLEGAL_STRINGS {
116        if path.contains(bad_str) {
117            return Err(Error::IllegalArgument(format!(
118                "Path cannot contain {:?}",
119                bad_str
120            )));
121        }
122    }
123
124    for component in path.split('/') {
125        for bad_str in PATH_ILLEGAL_COMPONENTS {
126            if component == *bad_str {
127                return Err(Error::IllegalArgument(format!(
128                    "Path cannot have component {:?}",
129                    component
130                )));
131            }
132        }
133
134        let component_lower = component.to_lowercase();
135        for bad_str in PATH_ILLEGAL_COMPONENTS_CASE_INSENSITIVE {
136            if component_lower.as_str() == *bad_str {
137                return Err(Error::IllegalArgument(format!(
138                    "Path cannot have component {:?}",
139                    component
140                )));
141            }
142        }
143    }
144
145    Ok(())
146}
147
148/// The TUF role.
149#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
150pub enum Role {
151    /// The root role.
152    #[serde(rename = "root")]
153    Root,
154
155    /// The snapshot role.
156    #[serde(rename = "snapshot")]
157    Snapshot,
158
159    /// The targets role.
160    #[serde(rename = "targets")]
161    Targets,
162
163    /// The timestamp role.
164    #[serde(rename = "timestamp")]
165    Timestamp,
166}
167
168impl Role {
169    /// Check if this role could be associated with a given path.
170    ///
171    /// ```
172    /// use tuf::metadata::{MetadataPath, Role};
173    ///
174    /// assert!(Role::Root.fuzzy_matches_path(&MetadataPath::root()));
175    /// assert!(Role::Snapshot.fuzzy_matches_path(&MetadataPath::snapshot()));
176    /// assert!(Role::Targets.fuzzy_matches_path(&MetadataPath::targets()));
177    /// assert!(Role::Timestamp.fuzzy_matches_path(&MetadataPath::timestamp()));
178    ///
179    /// assert!(!Role::Root.fuzzy_matches_path(&MetadataPath::snapshot()));
180    /// assert!(!Role::Root.fuzzy_matches_path(&MetadataPath::new("wat").unwrap()));
181    /// ```
182    pub fn fuzzy_matches_path(&self, path: &MetadataPath) -> bool {
183        match *self {
184            Role::Root if &path.0 == "root" => true,
185            Role::Snapshot if &path.0 == "snapshot" => true,
186            Role::Timestamp if &path.0 == "timestamp" => true,
187            Role::Targets if &path.0 == "targets" => true,
188            Role::Targets if !&["root", "snapshot", "targets"].contains(&path.0.as_ref()) => true,
189            _ => false,
190        }
191    }
192
193    /// Return the name of the role.
194    pub fn name(&self) -> &'static str {
195        match *self {
196            Role::Root => "root",
197            Role::Snapshot => "snapshot",
198            Role::Targets => "targets",
199            Role::Timestamp => "timestamp",
200        }
201    }
202}
203
204impl Display for Role {
205    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206        f.write_str(self.name())
207    }
208}
209
210/// Enum used for addressing versioned TUF metadata.
211#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
212pub enum MetadataVersion {
213    /// The metadata is unversioned. This is the latest version of the metadata.
214    None,
215    /// The metadata is addressed by a specific version number.
216    Number(u32),
217}
218
219impl Display for MetadataVersion {
220    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221        match self {
222            MetadataVersion::None => f.write_str("none"),
223            MetadataVersion::Number(version) => write!(f, "{}", version),
224        }
225    }
226}
227
228impl MetadataVersion {
229    /// Converts this struct into the string used for addressing metadata.
230    pub fn prefix(&self) -> String {
231        match *self {
232            MetadataVersion::None => String::new(),
233            MetadataVersion::Number(ref x) => format!("{}.", x),
234        }
235    }
236}
237
238/// Top level trait used for role metadata.
239pub trait Metadata: Debug + PartialEq + Serialize + DeserializeOwned {
240    /// The role associated with the metadata.
241    const ROLE: Role;
242
243    /// The version number.
244    fn version(&self) -> u32;
245
246    /// An immutable reference to the metadata's expiration `DateTime`.
247    fn expires(&self) -> &DateTime<Utc>;
248}
249
250/// Unverified raw metadata with attached signatures and type information identifying the
251/// metadata's type and serialization format.
252#[derive(Debug, Clone, PartialEq, Eq)]
253pub struct RawSignedMetadata<D, M> {
254    bytes: Vec<u8>,
255    _marker: PhantomData<(D, M)>,
256}
257
258impl<D, M> RawSignedMetadata<D, M>
259where
260    D: Pouf,
261    M: Metadata,
262{
263    /// Create a new [`RawSignedMetadata`] using the provided `bytes`.
264    pub fn new(bytes: Vec<u8>) -> Self {
265        Self {
266            bytes,
267            _marker: PhantomData,
268        }
269    }
270
271    /// Access this metadata's inner raw bytes.
272    pub fn as_bytes(&self) -> &[u8] {
273        &self.bytes
274    }
275
276    /// Parse this metadata.
277    ///
278    /// **WARNING**: This does not verify signatures, so it exposes users to potential parser
279    /// exploits.
280    pub fn parse_untrusted(&self) -> Result<SignedMetadata<D, M>> {
281        D::from_slice(&self.bytes)
282    }
283}
284
285/// A collection of [RawSignedMetadata] that describes the metadata at one
286/// commit.
287#[derive(Clone, Debug, Default, PartialEq, Eq)]
288pub struct RawSignedMetadataSet<D> {
289    root: Option<RawSignedMetadata<D, RootMetadata>>,
290    targets: Option<RawSignedMetadata<D, TargetsMetadata>>,
291    snapshot: Option<RawSignedMetadata<D, SnapshotMetadata>>,
292    timestamp: Option<RawSignedMetadata<D, TimestampMetadata>>,
293}
294
295impl<D> RawSignedMetadataSet<D> {
296    /// Returns a reference to the built root metadata, if any.
297    pub fn root(&self) -> Option<&RawSignedMetadata<D, RootMetadata>> {
298        self.root.as_ref()
299    }
300
301    /// Returns a reference to the built targets metadata, if any.
302    pub fn targets(&self) -> Option<&RawSignedMetadata<D, TargetsMetadata>> {
303        self.targets.as_ref()
304    }
305
306    /// Returns a reference to the built snapshot metadata, if any.
307    pub fn snapshot(&self) -> Option<&RawSignedMetadata<D, SnapshotMetadata>> {
308        self.snapshot.as_ref()
309    }
310
311    /// Returns a reference to the built timestamp metadata, if any.
312    pub fn timestamp(&self) -> Option<&RawSignedMetadata<D, TimestampMetadata>> {
313        self.timestamp.as_ref()
314    }
315}
316
317/// Builder for [RawSignedMetadataSet].
318#[derive(Default)]
319pub struct RawSignedMetadataSetBuilder<D>
320where
321    D: Pouf,
322{
323    metadata: RawSignedMetadataSet<D>,
324}
325
326impl<D> RawSignedMetadataSetBuilder<D>
327where
328    D: Pouf,
329{
330    /// Create a new [RawSignedMetadataSetBuilder].
331    pub fn new() -> Self {
332        Self {
333            metadata: RawSignedMetadataSet {
334                root: None,
335                targets: None,
336                snapshot: None,
337                timestamp: None,
338            },
339        }
340    }
341
342    /// Set or replace the root metadata.
343    pub fn root(mut self, root: RawSignedMetadata<D, RootMetadata>) -> Self {
344        self.metadata.root = Some(root);
345        self
346    }
347
348    /// Set or replace the targets metadata.
349    pub fn targets(mut self, targets: RawSignedMetadata<D, TargetsMetadata>) -> Self {
350        self.metadata.targets = Some(targets);
351        self
352    }
353
354    /// Set or replace the snapshot metadata.
355    pub fn snapshot(mut self, snapshot: RawSignedMetadata<D, SnapshotMetadata>) -> Self {
356        self.metadata.snapshot = Some(snapshot);
357        self
358    }
359
360    /// Set or replace the timestamp metadata.
361    pub fn timestamp(mut self, timestamp: RawSignedMetadata<D, TimestampMetadata>) -> Self {
362        self.metadata.timestamp = Some(timestamp);
363        self
364    }
365
366    /// Return a [RawSignedMetadataSet].
367    pub fn build(self) -> RawSignedMetadataSet<D> {
368        self.metadata
369    }
370}
371
372/// Helper to construct `SignedMetadata`.
373#[derive(Debug, Clone)]
374pub struct SignedMetadataBuilder<D, M>
375where
376    D: Pouf,
377{
378    signatures: HashMap<KeyId, Signature>,
379    metadata: D::RawData,
380    metadata_bytes: Vec<u8>,
381    _marker: PhantomData<M>,
382}
383
384impl<D, M> SignedMetadataBuilder<D, M>
385where
386    D: Pouf,
387    M: Metadata,
388{
389    /// Create a new `SignedMetadataBuilder` from a given `Metadata`.
390    pub fn from_metadata(metadata: &M) -> Result<Self> {
391        let metadata = D::serialize(metadata)?;
392        Self::from_raw_metadata(metadata)
393    }
394
395    /// Create a new `SignedMetadataBuilder` from manually serialized metadata to be signed.
396    /// Returns an error if `metadata` cannot be parsed into `M`.
397    pub fn from_raw_metadata(metadata: D::RawData) -> Result<Self> {
398        let _ensure_metadata_parses: M = D::deserialize(&metadata)?;
399        let metadata_bytes = D::canonicalize(&metadata)?;
400        Ok(Self {
401            signatures: HashMap::new(),
402            metadata,
403            metadata_bytes,
404            _marker: PhantomData,
405        })
406    }
407
408    /// Sign the metadata using the given `private_key`, replacing any existing signatures with the
409    /// same `KeyId`.
410    ///
411    /// **WARNING**: You should never have multiple TUF private keys on the same machine, so if
412    /// you're using this to append several signatures at once, you are doing something wrong. The
413    /// preferred method is to generate your copy of the metadata locally and use
414    /// `SignedMetadata::merge_signatures` to perform the "append" operations.
415    pub fn sign(mut self, private_key: &dyn PrivateKey) -> Result<Self> {
416        let sig = private_key.sign(&self.metadata_bytes)?;
417        let _ = self.signatures.insert(sig.key_id().clone(), sig);
418        Ok(self)
419    }
420
421    /// Construct a new `SignedMetadata` using the included signatures, sorting the signatures by
422    /// `KeyId`.
423    pub fn build(self) -> SignedMetadata<D, M> {
424        let mut signatures = self.signatures.into_values().collect::<Vec<_>>();
425        signatures.sort_unstable_by(|a, b| a.key_id().cmp(b.key_id()));
426
427        SignedMetadata {
428            signatures,
429            metadata: self.metadata,
430            _marker: PhantomData,
431        }
432    }
433}
434
435/// Serialized metadata with attached unverified signatures.
436#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
437pub struct SignedMetadata<D, M>
438where
439    D: Pouf,
440{
441    signatures: Vec<Signature>,
442    #[serde(rename = "signed")]
443    metadata: D::RawData,
444    #[serde(skip_serializing, skip_deserializing)]
445    _marker: PhantomData<M>,
446}
447
448impl<D, M> SignedMetadata<D, M>
449where
450    D: Pouf,
451    M: Metadata,
452{
453    /// Create a new `SignedMetadata`. The supplied private key is used to sign the canonicalized
454    /// bytes of the provided metadata with the provided scheme.
455    ///
456    /// ```
457    /// # use chrono::prelude::*;
458    /// # use tuf::crypto::{Ed25519PrivateKey, PrivateKey, SignatureScheme, HashAlgorithm};
459    /// # use tuf::pouf::Pouf1;
460    /// # use tuf::metadata::{SignedMetadata, SnapshotMetadataBuilder};
461    /// #
462    /// # let key: &[u8] = include_bytes!("../tests/ed25519/ed25519-1.pk8.der");
463    /// let key = Ed25519PrivateKey::from_pkcs8(&key).unwrap();
464    ///
465    /// let snapshot = SnapshotMetadataBuilder::new().build().unwrap();
466    /// SignedMetadata::<Pouf1, _>::new(&snapshot, &key).unwrap();
467    /// ```
468    pub fn new(metadata: &M, private_key: &dyn PrivateKey) -> Result<Self> {
469        let raw = D::serialize(metadata)?;
470        let bytes = D::canonicalize(&raw)?;
471        let sig = private_key.sign(&bytes)?;
472        Ok(Self {
473            signatures: vec![sig],
474            metadata: raw,
475            _marker: PhantomData,
476        })
477    }
478
479    /// Serialize this metadata to canonical bytes suitable for serialization. Note that this
480    /// method is only intended to serialize signed metadata generated by this crate, not to
481    /// re-serialize metadata that was originally obtained from a remote source.
482    ///
483    /// TUF metadata hashes are on the raw bytes of the metadata, so it is not guaranteed that the
484    /// hash of the returned bytes will match a hash included in, for example, a snapshot metadata
485    /// file, as:
486    /// * Parsing metadata removes unknown fields, which would not be included in the returned
487    ///   bytes,
488    /// * [Pouf] implementations only guarantee the bytes are canonical for the purpose of a
489    ///   signature. Metadata obtained from a remote source may have included different whitespace
490    ///   or ordered fields in a way that is not preserved when parsing that metadata.
491    pub fn to_raw(&self) -> Result<RawSignedMetadata<D, M>> {
492        let bytes = D::canonicalize(&D::serialize(self)?)?;
493        Ok(RawSignedMetadata::new(bytes))
494    }
495
496    /// Append a signature to this signed metadata. Will overwrite signature by keys with the same
497    /// ID.
498    ///
499    /// **WARNING**: You should never have multiple TUF private keys on the same machine, so if
500    /// you're using this to append several signatures at once, you are doing something wrong. The
501    /// preferred method is to generate your copy of the metadata locally and use `merge_signatures`
502    /// to perform the "append" operations.
503    ///
504    /// ```
505    /// # use chrono::prelude::*;
506    /// # use tuf::crypto::{Ed25519PrivateKey, PrivateKey, SignatureScheme, HashAlgorithm};
507    /// # use tuf::pouf::Pouf1;
508    /// # use tuf::metadata::{SignedMetadata, SnapshotMetadataBuilder};
509    /// #
510    /// let key_1: &[u8] = include_bytes!("../tests/ed25519/ed25519-1.pk8.der");
511    /// let key_1 = Ed25519PrivateKey::from_pkcs8(&key_1).unwrap();
512    ///
513    /// // Note: This is for demonstration purposes only.
514    /// // You should never have multiple private keys on the same device.
515    /// let key_2: &[u8] = include_bytes!("../tests/ed25519/ed25519-2.pk8.der");
516    /// let key_2 = Ed25519PrivateKey::from_pkcs8(&key_2).unwrap();
517    ///
518    /// let snapshot = SnapshotMetadataBuilder::new().build().unwrap();
519    /// let mut snapshot = SignedMetadata::<Pouf1, _>::new(&snapshot, &key_1).unwrap();
520    ///
521    /// snapshot.add_signature(&key_2).unwrap();
522    /// assert_eq!(snapshot.signatures().len(), 2);
523    ///
524    /// snapshot.add_signature(&key_2).unwrap();
525    /// assert_eq!(snapshot.signatures().len(), 2);
526    /// ```
527    pub fn add_signature(&mut self, private_key: &dyn PrivateKey) -> Result<()> {
528        let bytes = D::canonicalize(&self.metadata)?;
529        let sig = private_key.sign(&bytes)?;
530        self.signatures
531            .retain(|s| s.key_id() != private_key.public().key_id());
532        self.signatures.push(sig);
533        self.signatures.sort();
534        Ok(())
535    }
536
537    /// Merge the singatures from `other` into `self` if and only if
538    /// `self.as_ref() == other.as_ref()`. If `self` and `other` contain signatures from the same
539    /// key ID, then the signatures from `self` will replace the signatures from `other`.
540    pub fn merge_signatures(&mut self, other: &Self) -> Result<()> {
541        if self.metadata != other.metadata {
542            return Err(Error::IllegalArgument(
543                "Attempted to merge unequal metadata".into(),
544            ));
545        }
546
547        let key_ids = self
548            .signatures
549            .iter()
550            .map(|s| s.key_id().clone())
551            .collect::<HashSet<KeyId>>();
552
553        self.signatures.extend(
554            other
555                .signatures
556                .iter()
557                .filter(|s| !key_ids.contains(s.key_id()))
558                .cloned(),
559        );
560        self.signatures.sort();
561
562        Ok(())
563    }
564
565    /// An immutable reference to the signatures.
566    pub fn signatures(&self) -> &[Signature] {
567        &self.signatures
568    }
569
570    /// Parse the version number of this metadata without verifying signatures.
571    ///
572    /// This operation is generally unsafe to do with metadata obtained from an untrusted source,
573    /// but rolling forward to the most recent root.json requires using the version number of the
574    /// latest root.json.
575    pub(crate) fn parse_version_untrusted(&self) -> Result<u32> {
576        #[derive(Deserialize)]
577        pub struct MetadataVersion {
578            version: u32,
579        }
580
581        let meta: MetadataVersion = D::deserialize(&self.metadata)?;
582        Ok(meta.version)
583    }
584
585    /// Parse this metadata without verifying signatures.
586    ///
587    /// This operation is not safe to do with metadata obtained from an untrusted source.
588    pub fn assume_valid(&self) -> Result<M> {
589        D::deserialize(&self.metadata)
590    }
591}
592
593/// Helper to construct `RootMetadata`.
594pub struct RootMetadataBuilder {
595    version: u32,
596    expires: DateTime<Utc>,
597    consistent_snapshot: bool,
598    keys: HashMap<KeyId, PublicKey>,
599    root_threshold: u32,
600    root_key_ids: HashSet<KeyId>,
601    snapshot_threshold: u32,
602    snapshot_key_ids: HashSet<KeyId>,
603    targets_threshold: u32,
604    targets_key_ids: HashSet<KeyId>,
605    timestamp_threshold: u32,
606    timestamp_key_ids: HashSet<KeyId>,
607}
608
609impl RootMetadataBuilder {
610    /// Create a new `RootMetadataBuilder`. It defaults to:
611    ///
612    /// * version: 1,
613    /// * expires: 365 days from the current time.
614    /// * consistent snapshot: true
615    /// * role thresholds: 1
616    pub fn new() -> Self {
617        RootMetadataBuilder {
618            version: 1,
619            expires: Utc::now() + Duration::days(365),
620            consistent_snapshot: true,
621            keys: HashMap::new(),
622            root_threshold: 1,
623            root_key_ids: HashSet::new(),
624            snapshot_threshold: 1,
625            snapshot_key_ids: HashSet::new(),
626            targets_threshold: 1,
627            targets_key_ids: HashSet::new(),
628            timestamp_threshold: 1,
629            timestamp_key_ids: HashSet::new(),
630        }
631    }
632
633    /// Set the version number for this metadata.
634    pub fn version(mut self, version: u32) -> Self {
635        self.version = version;
636        self
637    }
638
639    /// Set the time this metadata expires.
640    pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
641        self.expires = expires;
642        self
643    }
644
645    /// Set this metadata to have a consistent snapshot.
646    pub fn consistent_snapshot(mut self, consistent_snapshot: bool) -> Self {
647        self.consistent_snapshot = consistent_snapshot;
648        self
649    }
650
651    /// Set the root threshold.
652    pub fn root_threshold(mut self, threshold: u32) -> Self {
653        self.root_threshold = threshold;
654        self
655    }
656
657    /// Add a root public key.
658    pub fn root_key(mut self, public_key: PublicKey) -> Self {
659        let key_id = public_key.key_id().clone();
660        self.keys.insert(key_id.clone(), public_key);
661        self.root_key_ids.insert(key_id);
662        self
663    }
664
665    /// Set the snapshot threshold.
666    pub fn snapshot_threshold(mut self, threshold: u32) -> Self {
667        self.snapshot_threshold = threshold;
668        self
669    }
670
671    /// Add a snapshot public key.
672    pub fn snapshot_key(mut self, public_key: PublicKey) -> Self {
673        let key_id = public_key.key_id().clone();
674        self.keys.insert(key_id.clone(), public_key);
675        self.snapshot_key_ids.insert(key_id);
676        self
677    }
678
679    /// Set the targets threshold.
680    pub fn targets_threshold(mut self, threshold: u32) -> Self {
681        self.targets_threshold = threshold;
682        self
683    }
684
685    /// Add a targets public key.
686    pub fn targets_key(mut self, public_key: PublicKey) -> Self {
687        let key_id = public_key.key_id().clone();
688        self.keys.insert(key_id.clone(), public_key);
689        self.targets_key_ids.insert(key_id);
690        self
691    }
692
693    /// Set the timestamp threshold.
694    pub fn timestamp_threshold(mut self, threshold: u32) -> Self {
695        self.timestamp_threshold = threshold;
696        self
697    }
698
699    /// Add a timestamp public key.
700    pub fn timestamp_key(mut self, public_key: PublicKey) -> Self {
701        let key_id = public_key.key_id().clone();
702        self.keys.insert(key_id.clone(), public_key);
703        self.timestamp_key_ids.insert(key_id);
704        self
705    }
706
707    /// Construct a new `RootMetadata`.
708    pub fn build(self) -> Result<RootMetadata> {
709        RootMetadata::new(
710            self.version,
711            self.expires,
712            self.consistent_snapshot,
713            self.keys,
714            RoleDefinition::new(self.root_threshold, self.root_key_ids)?,
715            RoleDefinition::new(self.snapshot_threshold, self.snapshot_key_ids)?,
716            RoleDefinition::new(self.targets_threshold, self.targets_key_ids)?,
717            RoleDefinition::new(self.timestamp_threshold, self.timestamp_key_ids)?,
718            Default::default(),
719        )
720    }
721
722    /// Construct a new `SignedMetadata<D, RootMetadata>`.
723    pub fn signed<D>(self, private_key: &dyn PrivateKey) -> Result<SignedMetadata<D, RootMetadata>>
724    where
725        D: Pouf,
726    {
727        SignedMetadata::new(&self.build()?, private_key)
728    }
729}
730
731impl Default for RootMetadataBuilder {
732    fn default() -> Self {
733        RootMetadataBuilder::new()
734    }
735}
736
737impl From<RootMetadata> for RootMetadataBuilder {
738    fn from(metadata: RootMetadata) -> Self {
739        RootMetadataBuilder {
740            version: metadata.version,
741            expires: metadata.expires,
742            consistent_snapshot: metadata.consistent_snapshot,
743            keys: metadata.keys,
744            root_threshold: metadata.root.threshold,
745            root_key_ids: metadata.root.key_ids,
746            snapshot_threshold: metadata.snapshot.threshold,
747            snapshot_key_ids: metadata.snapshot.key_ids,
748            targets_threshold: metadata.targets.threshold,
749            targets_key_ids: metadata.targets.key_ids,
750            timestamp_threshold: metadata.timestamp.threshold,
751            timestamp_key_ids: metadata.timestamp.key_ids,
752        }
753    }
754}
755
756/// Metadata for the root role.
757#[derive(Debug, Clone, PartialEq, Eq)]
758pub struct RootMetadata {
759    version: u32,
760    expires: DateTime<Utc>,
761    consistent_snapshot: bool,
762    keys: HashMap<KeyId, PublicKey>,
763    root: RoleDefinition<RootMetadata>,
764    snapshot: RoleDefinition<SnapshotMetadata>,
765    targets: RoleDefinition<TargetsMetadata>,
766    timestamp: RoleDefinition<TimestampMetadata>,
767    additional_fields: HashMap<String, serde_json::Value>,
768}
769
770impl RootMetadata {
771    /// Create new `RootMetadata`.
772    pub fn new(
773        version: u32,
774        expires: DateTime<Utc>,
775        consistent_snapshot: bool,
776        keys: HashMap<KeyId, PublicKey>,
777        root: RoleDefinition<RootMetadata>,
778        snapshot: RoleDefinition<SnapshotMetadata>,
779        targets: RoleDefinition<TargetsMetadata>,
780        timestamp: RoleDefinition<TimestampMetadata>,
781        additional_fields: HashMap<String, serde_json::Value>,
782    ) -> Result<Self> {
783        if version < 1 {
784            return Err(Error::MetadataVersionMustBeGreaterThanZero(
785                MetadataPath::root(),
786            ));
787        }
788
789        Ok(RootMetadata {
790            version,
791            expires,
792            consistent_snapshot,
793            keys,
794            root,
795            snapshot,
796            targets,
797            timestamp,
798            additional_fields,
799        })
800    }
801
802    /// Whether or not this repository is currently implementing that TUF consistent snapshot
803    /// feature.
804    pub fn consistent_snapshot(&self) -> bool {
805        self.consistent_snapshot
806    }
807
808    /// An immutable reference to the map of trusted keys.
809    pub fn keys(&self) -> &HashMap<KeyId, PublicKey> {
810        &self.keys
811    }
812
813    /// An iterator over all the trusted root public keys.
814    pub fn root_keys(&self) -> impl Iterator<Item = &PublicKey> {
815        self.root
816            .key_ids()
817            .iter()
818            .filter_map(|key_id| self.keys.get(key_id))
819    }
820
821    /// An iterator over all the trusted targets public keys.
822    pub fn targets_keys(&self) -> impl Iterator<Item = &PublicKey> {
823        self.targets
824            .key_ids()
825            .iter()
826            .filter_map(|key_id| self.keys.get(key_id))
827    }
828
829    /// An iterator over all the trusted snapshot public keys.
830    pub fn snapshot_keys(&self) -> impl Iterator<Item = &PublicKey> {
831        self.snapshot
832            .key_ids()
833            .iter()
834            .filter_map(|key_id| self.keys.get(key_id))
835    }
836
837    /// An iterator over all the trusted timestamp public keys.
838    pub fn timestamp_keys(&self) -> impl Iterator<Item = &PublicKey> {
839        self.timestamp
840            .key_ids()
841            .iter()
842            .filter_map(|key_id| self.keys.get(key_id))
843    }
844
845    /// An immutable reference to the root role's definition.
846    pub fn root(&self) -> &RoleDefinition<RootMetadata> {
847        &self.root
848    }
849
850    /// An immutable reference to the snapshot role's definition.
851    pub fn snapshot(&self) -> &RoleDefinition<SnapshotMetadata> {
852        &self.snapshot
853    }
854
855    /// An immutable reference to the targets role's definition.
856    pub fn targets(&self) -> &RoleDefinition<TargetsMetadata> {
857        &self.targets
858    }
859
860    /// An immutable reference to the timestamp role's definition.
861    pub fn timestamp(&self) -> &RoleDefinition<TimestampMetadata> {
862        &self.timestamp
863    }
864
865    /// An immutable reference to any additional fields on the metadata.
866    pub fn additional_fields(&self) -> &HashMap<String, serde_json::Value> {
867        &self.additional_fields
868    }
869}
870
871impl Metadata for RootMetadata {
872    const ROLE: Role = Role::Root;
873
874    fn version(&self) -> u32 {
875        self.version
876    }
877
878    fn expires(&self) -> &DateTime<Utc> {
879        &self.expires
880    }
881}
882
883impl Serialize for RootMetadata {
884    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
885    where
886        S: Serializer,
887    {
888        let m = shims::RootMetadata::from(self)
889            .map_err(|e| SerializeError::custom(format!("{:?}", e)))?;
890        m.serialize(ser)
891    }
892}
893
894impl<'de> Deserialize<'de> for RootMetadata {
895    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
896        let intermediate: shims::RootMetadata = Deserialize::deserialize(de)?;
897        intermediate
898            .try_into()
899            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
900    }
901}
902
903/// The definition of what allows a role to be trusted.
904#[derive(Clone, Debug, PartialEq, Eq)]
905pub struct RoleDefinition<M: Metadata> {
906    threshold: u32,
907    key_ids: HashSet<KeyId>,
908    _metadata: PhantomData<M>,
909}
910
911impl<M: Metadata> RoleDefinition<M> {
912    /// Create a new [RoleDefinition] with a given threshold and set of authorized [KeyId]s.
913    pub fn new(threshold: u32, key_ids: HashSet<KeyId>) -> Result<Self> {
914        if threshold < 1 {
915            return Err(Error::MetadataThresholdMustBeGreaterThanZero(
916                M::ROLE.into(),
917            ));
918        }
919
920        if (key_ids.len() as u64) < u64::from(threshold) {
921            return Err(Error::MetadataRoleDoesNotHaveEnoughKeyIds {
922                role: M::ROLE.into(),
923                key_ids: key_ids.len(),
924                threshold,
925            });
926        }
927
928        Ok(RoleDefinition {
929            threshold,
930            key_ids,
931            _metadata: PhantomData,
932        })
933    }
934
935    /// The threshold number of signatures required for the role to be trusted.
936    pub fn threshold(&self) -> u32 {
937        self.threshold
938    }
939
940    /// An immutable reference to the set of `KeyID`s that are authorized to sign the role.
941    pub fn key_ids(&self) -> &HashSet<KeyId> {
942        &self.key_ids
943    }
944}
945
946impl<M: Metadata> Serialize for RoleDefinition<M> {
947    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
948    where
949        S: Serializer,
950    {
951        shims::RoleDefinition::from(self).serialize(ser)
952    }
953}
954
955impl<'de, M: Metadata> Deserialize<'de> for RoleDefinition<M> {
956    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
957        let intermediate = shims::RoleDefinition::deserialize(de)?;
958        intermediate
959            .try_into()
960            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
961    }
962}
963
964/// Wrapper for a path to metadata.
965///
966/// Note: This should **not** contain the file extension. This is automatically added by the
967/// library depending on what type of data pouf format is being used.
968///
969/// ```
970/// use tuf::metadata::MetadataPath;
971///
972/// // right
973/// let _ = MetadataPath::new("root");
974///
975/// // wrong
976/// let _ = MetadataPath::new("root.json");
977/// ```
978#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
979pub struct MetadataPath(Cow<'static, str>);
980
981impl MetadataPath {
982    /// Create a new `MetadataPath` for the Root role.
983    pub fn root() -> Self {
984        MetadataPath(Role::Root.name().into())
985    }
986
987    /// Create a new `MetadataPath` for the Timestamp role.
988    pub fn timestamp() -> Self {
989        MetadataPath(Role::Timestamp.name().into())
990    }
991
992    /// Create a new `MetadataPath` for the Snapshot role.
993    pub fn snapshot() -> Self {
994        MetadataPath(Role::Snapshot.name().into())
995    }
996
997    /// Create a new `MetadataPath` for the targets role.
998    pub fn targets() -> Self {
999        MetadataPath(Role::Targets.name().into())
1000    }
1001
1002    /// Create a new `MetadataPath` from a `String`.
1003    ///
1004    /// ```
1005    /// # use tuf::metadata::MetadataPath;
1006    /// assert!(MetadataPath::new("foo").is_ok());
1007    /// assert!(MetadataPath::new("/foo").is_err());
1008    /// assert!(MetadataPath::new("../foo").is_err());
1009    /// assert!(MetadataPath::new("foo/..").is_err());
1010    /// assert!(MetadataPath::new("foo/../bar").is_err());
1011    /// assert!(MetadataPath::new("..foo").is_ok());
1012    /// assert!(MetadataPath::new("foo/..bar").is_ok());
1013    /// assert!(MetadataPath::new("foo/bar..").is_ok());
1014    /// ```
1015    pub fn new<P: Into<Cow<'static, str>>>(path: P) -> Result<Self> {
1016        let path = path.into();
1017        match path.as_ref() {
1018            "root" => Ok(MetadataPath::root()),
1019            "timestamp" => Ok(MetadataPath::timestamp()),
1020            "snapshot" => Ok(MetadataPath::snapshot()),
1021            "targets" => Ok(MetadataPath::targets()),
1022            _ => {
1023                safe_path(&path)?;
1024                Ok(MetadataPath(path))
1025            }
1026        }
1027    }
1028
1029    /// Split `MetadataPath` into components that can be joined to create URL paths, Unix paths, or
1030    /// Windows paths.
1031    ///
1032    /// ```
1033    /// # use tuf::crypto::HashValue;
1034    /// # use tuf::pouf::Pouf1;
1035    /// # use tuf::metadata::{MetadataPath, MetadataVersion};
1036    /// #
1037    /// let path = MetadataPath::new("foo/bar").unwrap();
1038    /// assert_eq!(path.components::<Pouf1>(MetadataVersion::None),
1039    ///            ["foo".to_string(), "bar.json".to_string()]);
1040    /// assert_eq!(path.components::<Pouf1>(MetadataVersion::Number(1)),
1041    ///            ["foo".to_string(), "1.bar.json".to_string()]);
1042    /// ```
1043    pub fn components<D>(&self, version: MetadataVersion) -> Vec<String>
1044    where
1045        D: Pouf,
1046    {
1047        let mut buf: Vec<String> = self.0.split('/').map(|s| s.to_string()).collect();
1048        let len = buf.len();
1049        buf[len - 1] = format!("{}{}.{}", version.prefix(), buf[len - 1], D::extension());
1050        buf
1051    }
1052}
1053
1054impl From<Role> for MetadataPath {
1055    fn from(role: Role) -> MetadataPath {
1056        match role {
1057            Role::Root => MetadataPath::root(),
1058            Role::Timestamp => MetadataPath::timestamp(),
1059            Role::Snapshot => MetadataPath::snapshot(),
1060            Role::Targets => MetadataPath::targets(),
1061        }
1062    }
1063}
1064
1065impl Display for MetadataPath {
1066    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1067        f.write_str(&self.0)
1068    }
1069}
1070
1071impl<'de> Deserialize<'de> for MetadataPath {
1072    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
1073        let s: String = Deserialize::deserialize(de)?;
1074        MetadataPath::new(s).map_err(|e| DeserializeError::custom(format!("{:?}", e)))
1075    }
1076}
1077
1078/// Helper to construct `TimestampMetadata`.
1079pub struct TimestampMetadataBuilder {
1080    version: u32,
1081    expires: DateTime<Utc>,
1082    snapshot: MetadataDescription<SnapshotMetadata>,
1083}
1084
1085impl TimestampMetadataBuilder {
1086    /// Create a new `TimestampMetadataBuilder` from a given snapshot. It defaults to:
1087    ///
1088    /// * version: 1
1089    /// * expires: 1 day from the current time.
1090    pub fn from_snapshot<D>(
1091        snapshot: &SignedMetadata<D, SnapshotMetadata>,
1092        hash_algs: &[HashAlgorithm],
1093    ) -> Result<Self>
1094    where
1095        D: Pouf,
1096    {
1097        let raw_snapshot = snapshot.to_raw()?;
1098        let description = MetadataDescription::from_slice(
1099            raw_snapshot.as_bytes(),
1100            snapshot.parse_version_untrusted()?,
1101            hash_algs,
1102        )?;
1103
1104        Ok(Self::from_metadata_description(description))
1105    }
1106
1107    /// Create a new `TimestampMetadataBuilder` from a given
1108    /// `MetadataDescription`. It defaults to:
1109    ///
1110    /// * version: 1
1111    /// * expires: 1 day from the current time.
1112    pub fn from_metadata_description(description: MetadataDescription<SnapshotMetadata>) -> Self {
1113        TimestampMetadataBuilder {
1114            version: 1,
1115            expires: Utc::now() + Duration::days(1),
1116            snapshot: description,
1117        }
1118    }
1119
1120    /// Set the version number for this metadata.
1121    pub fn version(mut self, version: u32) -> Self {
1122        self.version = version;
1123        self
1124    }
1125
1126    /// Set the time this metadata expires.
1127    pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
1128        self.expires = expires;
1129        self
1130    }
1131
1132    /// Construct a new `TimestampMetadata`.
1133    pub fn build(self) -> Result<TimestampMetadata> {
1134        TimestampMetadata::new(
1135            self.version,
1136            self.expires,
1137            self.snapshot,
1138            Default::default(),
1139        )
1140    }
1141
1142    /// Construct a new `SignedMetadata<D, TimestampMetadata>`.
1143    pub fn signed<D>(
1144        self,
1145        private_key: &dyn PrivateKey,
1146    ) -> Result<SignedMetadata<D, TimestampMetadata>>
1147    where
1148        D: Pouf,
1149    {
1150        SignedMetadata::new(&self.build()?, private_key)
1151    }
1152}
1153
1154/// Metadata for the timestamp role.
1155#[derive(Debug, Clone, PartialEq, Eq)]
1156pub struct TimestampMetadata {
1157    version: u32,
1158    expires: DateTime<Utc>,
1159    snapshot: MetadataDescription<SnapshotMetadata>,
1160    additional_fields: HashMap<String, serde_json::Value>,
1161}
1162
1163impl TimestampMetadata {
1164    /// Create new `TimestampMetadata`.
1165    pub fn new(
1166        version: u32,
1167        expires: DateTime<Utc>,
1168        snapshot: MetadataDescription<SnapshotMetadata>,
1169        additional_fields: HashMap<String, serde_json::Value>,
1170    ) -> Result<Self> {
1171        if version < 1 {
1172            return Err(Error::MetadataVersionMustBeGreaterThanZero(
1173                MetadataPath::timestamp(),
1174            ));
1175        }
1176
1177        Ok(TimestampMetadata {
1178            version,
1179            expires,
1180            snapshot,
1181            additional_fields,
1182        })
1183    }
1184
1185    /// An immutable reference to the snapshot description.
1186    pub fn snapshot(&self) -> &MetadataDescription<SnapshotMetadata> {
1187        &self.snapshot
1188    }
1189
1190    /// An immutable reference to any additional fields on the metadata.
1191    pub fn additional_fields(&self) -> &HashMap<String, serde_json::Value> {
1192        &self.additional_fields
1193    }
1194}
1195
1196impl Metadata for TimestampMetadata {
1197    const ROLE: Role = Role::Timestamp;
1198
1199    fn version(&self) -> u32 {
1200        self.version
1201    }
1202
1203    fn expires(&self) -> &DateTime<Utc> {
1204        &self.expires
1205    }
1206}
1207
1208impl Serialize for TimestampMetadata {
1209    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
1210    where
1211        S: Serializer,
1212    {
1213        shims::TimestampMetadata::from(self)
1214            .map_err(|e| SerializeError::custom(format!("{:?}", e)))?
1215            .serialize(ser)
1216    }
1217}
1218
1219impl<'de> Deserialize<'de> for TimestampMetadata {
1220    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
1221        let intermediate: shims::TimestampMetadata = Deserialize::deserialize(de)?;
1222        intermediate
1223            .try_into()
1224            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
1225    }
1226}
1227
1228/// Description of a piece of metadata, used in verification.
1229#[derive(Debug, Clone, PartialEq, Eq)]
1230pub struct MetadataDescription<M: Metadata> {
1231    version: u32,
1232    length: Option<usize>,
1233    hashes: HashMap<HashAlgorithm, HashValue>,
1234    _metadata: PhantomData<M>,
1235}
1236
1237impl<M: Metadata> MetadataDescription<M> {
1238    /// Create a `MetadataDescription` from a slice. Size and hashes will be calculated.
1239    pub fn from_slice(buf: &[u8], version: u32, hash_algs: &[HashAlgorithm]) -> Result<Self> {
1240        if version < 1 {
1241            return Err(Error::IllegalArgument(
1242                "Version must be greater than zero".into(),
1243            ));
1244        }
1245
1246        let hashes = if hash_algs.is_empty() {
1247            HashMap::new()
1248        } else {
1249            crypto::calculate_hashes_from_slice(buf, hash_algs)?
1250        };
1251
1252        Ok(MetadataDescription {
1253            version,
1254            length: Some(buf.len()),
1255            hashes,
1256            _metadata: PhantomData,
1257        })
1258    }
1259
1260    /// Create a new `MetadataDescription`.
1261    pub fn new(
1262        version: u32,
1263        length: Option<usize>,
1264        hashes: HashMap<HashAlgorithm, HashValue>,
1265    ) -> Result<Self> {
1266        if version < 1 {
1267            return Err(Error::MetadataVersionMustBeGreaterThanZero(M::ROLE.into()));
1268        }
1269
1270        Ok(MetadataDescription {
1271            version,
1272            length,
1273            hashes,
1274            _metadata: PhantomData,
1275        })
1276    }
1277
1278    /// The version of the described metadata.
1279    pub fn version(&self) -> u32 {
1280        self.version
1281    }
1282
1283    /// The length of the described metadata.
1284    pub fn length(&self) -> Option<usize> {
1285        self.length
1286    }
1287
1288    /// An immutable reference to the hashes of the described metadata.
1289    pub fn hashes(&self) -> &HashMap<HashAlgorithm, HashValue> {
1290        &self.hashes
1291    }
1292}
1293
1294impl<M: Metadata> Serialize for MetadataDescription<M> {
1295    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
1296    where
1297        S: Serializer,
1298    {
1299        shims::MetadataDescription::from(self).serialize(ser)
1300    }
1301}
1302
1303impl<'de, M: Metadata> Deserialize<'de> for MetadataDescription<M> {
1304    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
1305        let intermediate = shims::MetadataDescription::deserialize(de)?;
1306        intermediate
1307            .try_into()
1308            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
1309    }
1310}
1311
1312/// Helper to construct `SnapshotMetadata`.
1313pub struct SnapshotMetadataBuilder {
1314    version: u32,
1315    expires: DateTime<Utc>,
1316    meta: HashMap<MetadataPath, MetadataDescription<TargetsMetadata>>,
1317}
1318
1319impl SnapshotMetadataBuilder {
1320    /// Create a new `SnapshotMetadataBuilder`. It defaults to:
1321    ///
1322    /// * version: 1
1323    /// * expires: 7 days from the current time.
1324    pub fn new() -> Self {
1325        SnapshotMetadataBuilder {
1326            version: 1,
1327            expires: Utc::now() + Duration::days(7),
1328            meta: HashMap::new(),
1329        }
1330    }
1331
1332    /// Create a new [SnapshotMetadataBuilder] from a given snapshot. It defaults to:
1333    ///
1334    /// * version: 1
1335    /// * expires: 7 day from the current time.
1336    pub fn from_targets<D>(
1337        targets: &SignedMetadata<D, TargetsMetadata>,
1338        hash_algs: &[HashAlgorithm],
1339    ) -> Result<Self>
1340    where
1341        D: Pouf,
1342    {
1343        SnapshotMetadataBuilder::new().insert_metadata(targets, hash_algs)
1344    }
1345
1346    /// Set the version number for this metadata.
1347    pub fn version(mut self, version: u32) -> Self {
1348        self.version = version;
1349        self
1350    }
1351
1352    /// Set the time this metadata expires.
1353    pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
1354        self.expires = expires;
1355        self
1356    }
1357
1358    /// Add metadata to this snapshot metadata using the default path.
1359    pub fn insert_metadata<D, M>(
1360        self,
1361        metadata: &SignedMetadata<D, M>,
1362        hash_algs: &[HashAlgorithm],
1363    ) -> Result<Self>
1364    where
1365        M: Metadata,
1366        D: Pouf,
1367    {
1368        self.insert_metadata_with_path(M::ROLE.name(), metadata, hash_algs)
1369    }
1370
1371    /// Add metadata to this snapshot metadata using a custom path.
1372    pub fn insert_metadata_with_path<P, D, M>(
1373        self,
1374        path: P,
1375        metadata: &SignedMetadata<D, M>,
1376        hash_algs: &[HashAlgorithm],
1377    ) -> Result<Self>
1378    where
1379        P: Into<Cow<'static, str>>,
1380        M: Metadata,
1381        D: Pouf,
1382    {
1383        let raw_metadata = metadata.to_raw()?;
1384        let description = MetadataDescription::from_slice(
1385            raw_metadata.as_bytes(),
1386            metadata.parse_version_untrusted()?,
1387            hash_algs,
1388        )?;
1389        let path = MetadataPath::new(path)?;
1390        Ok(self.insert_metadata_description(path, description))
1391    }
1392
1393    /// Add `MetadataDescription` to this snapshot metadata using a custom path.
1394    pub fn insert_metadata_description(
1395        mut self,
1396        path: MetadataPath,
1397        description: MetadataDescription<TargetsMetadata>,
1398    ) -> Self {
1399        self.meta.insert(path, description);
1400        self
1401    }
1402
1403    /// Construct a new `SnapshotMetadata`.
1404    pub fn build(self) -> Result<SnapshotMetadata> {
1405        SnapshotMetadata::new(self.version, self.expires, self.meta, Default::default())
1406    }
1407
1408    /// Construct a new `SignedMetadata<D, SnapshotMetadata>`.
1409    pub fn signed<D>(
1410        self,
1411        private_key: &dyn PrivateKey,
1412    ) -> Result<SignedMetadata<D, SnapshotMetadata>>
1413    where
1414        D: Pouf,
1415    {
1416        SignedMetadata::new(&self.build()?, private_key)
1417    }
1418}
1419
1420impl Default for SnapshotMetadataBuilder {
1421    fn default() -> Self {
1422        SnapshotMetadataBuilder::new()
1423    }
1424}
1425
1426impl From<SnapshotMetadata> for SnapshotMetadataBuilder {
1427    fn from(meta: SnapshotMetadata) -> Self {
1428        SnapshotMetadataBuilder {
1429            version: meta.version,
1430            expires: meta.expires,
1431            meta: meta.meta,
1432        }
1433    }
1434}
1435
1436/// Metadata for the snapshot role.
1437#[derive(Debug, Clone, PartialEq, Eq)]
1438pub struct SnapshotMetadata {
1439    version: u32,
1440    expires: DateTime<Utc>,
1441    meta: HashMap<MetadataPath, MetadataDescription<TargetsMetadata>>,
1442    additional_fields: HashMap<String, serde_json::Value>,
1443}
1444
1445impl SnapshotMetadata {
1446    /// Create new `SnapshotMetadata`.
1447    pub fn new(
1448        version: u32,
1449        expires: DateTime<Utc>,
1450        meta: HashMap<MetadataPath, MetadataDescription<TargetsMetadata>>,
1451        additional_fields: HashMap<String, serde_json::Value>,
1452    ) -> Result<Self> {
1453        if version < 1 {
1454            return Err(Error::MetadataVersionMustBeGreaterThanZero(
1455                MetadataPath::snapshot(),
1456            ));
1457        }
1458
1459        Ok(SnapshotMetadata {
1460            version,
1461            expires,
1462            meta,
1463            additional_fields,
1464        })
1465    }
1466
1467    /// An immutable reference to the metadata paths and descriptions.
1468    pub fn meta(&self) -> &HashMap<MetadataPath, MetadataDescription<TargetsMetadata>> {
1469        &self.meta
1470    }
1471
1472    /// An immutable reference to any additional fields on the metadata.
1473    pub fn additional_fields(&self) -> &HashMap<String, serde_json::Value> {
1474        &self.additional_fields
1475    }
1476}
1477
1478impl Metadata for SnapshotMetadata {
1479    const ROLE: Role = Role::Snapshot;
1480
1481    fn version(&self) -> u32 {
1482        self.version
1483    }
1484
1485    fn expires(&self) -> &DateTime<Utc> {
1486        &self.expires
1487    }
1488}
1489
1490impl Serialize for SnapshotMetadata {
1491    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
1492    where
1493        S: Serializer,
1494    {
1495        shims::SnapshotMetadata::from(self)
1496            .map_err(|e| SerializeError::custom(format!("{:?}", e)))?
1497            .serialize(ser)
1498    }
1499}
1500
1501impl<'de> Deserialize<'de> for SnapshotMetadata {
1502    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
1503        let intermediate: shims::SnapshotMetadata = Deserialize::deserialize(de)?;
1504        intermediate
1505            .try_into()
1506            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
1507    }
1508}
1509
1510/// Wrapper for the virtual path to a target.
1511#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Serialize)]
1512pub struct TargetPath(String);
1513
1514impl TargetPath {
1515    /// Create a new `TargetPath` from a `String`.
1516    ///
1517    /// ```
1518    /// # use tuf::metadata::TargetPath;
1519    /// assert!(TargetPath::new("foo").is_ok());
1520    /// assert!(TargetPath::new("/foo").is_err());
1521    /// assert!(TargetPath::new("../foo").is_err());
1522    /// assert!(TargetPath::new("foo/..").is_err());
1523    /// assert!(TargetPath::new("foo/../bar").is_err());
1524    /// assert!(TargetPath::new("..foo").is_ok());
1525    /// assert!(TargetPath::new("foo/..bar").is_ok());
1526    /// assert!(TargetPath::new("foo/bar..").is_ok());
1527    /// ```
1528    pub fn new<P: Into<String>>(path: P) -> Result<Self> {
1529        let path = path.into();
1530        safe_path(&path)?;
1531        Ok(TargetPath(path))
1532    }
1533
1534    /// Split `TargetPath` into components that can be joined to create URL paths, Unix
1535    /// paths, or Windows paths.
1536    ///
1537    /// ```
1538    /// # use tuf::metadata::TargetPath;
1539    /// let path = TargetPath::new("foo/bar").unwrap();
1540    /// assert_eq!(path.components(), ["foo".to_string(), "bar".to_string()]);
1541    /// ```
1542    pub fn components(&self) -> Vec<String> {
1543        self.0.split('/').map(|s| s.to_string()).collect()
1544    }
1545
1546    /// Return whether this path is the child of another path.
1547    ///
1548    /// ```
1549    /// # use tuf::metadata::TargetPath;
1550    /// let path1 = TargetPath::new("foo").unwrap();
1551    /// let path2 = TargetPath::new("foo/bar").unwrap();
1552    /// assert!(!path2.is_child(&path1));
1553    ///
1554    /// let path1 = TargetPath::new("foo/").unwrap();
1555    /// let path2 = TargetPath::new("foo/bar").unwrap();
1556    /// assert!(path2.is_child(&path1));
1557    ///
1558    /// let path2 = TargetPath::new("foo/bar/baz").unwrap();
1559    /// assert!(path2.is_child(&path1));
1560    ///
1561    /// let path2 = TargetPath::new("wat").unwrap();
1562    /// assert!(!path2.is_child(&path1))
1563    /// ```
1564    pub fn is_child(&self, parent: &Self) -> bool {
1565        if !parent.0.ends_with('/') {
1566            return false;
1567        }
1568
1569        self.0.starts_with(&parent.0)
1570    }
1571
1572    /// Whether or not the current target is available at the end of the given chain of target
1573    /// paths. For the chain to be valid, each target path in a group must be a child of of all
1574    /// previous groups.
1575    // TODO this is hideous and uses way too much clone/heap but I think recursively,
1576    // so here we are
1577    pub fn matches_chain(&self, parents: &[HashSet<TargetPath>]) -> bool {
1578        if parents.is_empty() {
1579            return false;
1580        }
1581        if parents.len() == 1 {
1582            return parents[0].iter().any(|p| p == self || self.is_child(p));
1583        }
1584
1585        let new = parents[1..]
1586            .iter()
1587            .map(|group| {
1588                group
1589                    .iter()
1590                    .filter(|parent| {
1591                        parents[0]
1592                            .iter()
1593                            .any(|p| parent.is_child(p) || parent == &p)
1594                    })
1595                    .cloned()
1596                    .collect::<HashSet<_>>()
1597            })
1598            .collect::<Vec<_>>();
1599        self.matches_chain(&new)
1600    }
1601
1602    /// Prefix the target path with a hash value to support TUF spec 5.5.2.
1603    pub fn with_hash_prefix(&self, hash: &HashValue) -> Result<TargetPath> {
1604        let mut components = self.components();
1605
1606        let file_name = components
1607            .pop()
1608            .ok_or_else(|| Error::IllegalArgument("Path cannot be empty".into()))?;
1609
1610        components.push(format!("{}.{}", hash, file_name));
1611
1612        TargetPath::new(components.join("/"))
1613    }
1614
1615    /// The string value of the path.
1616    pub fn as_str(&self) -> &str {
1617        &self.0
1618    }
1619}
1620
1621impl Display for TargetPath {
1622    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1623        f.write_str(&self.0)
1624    }
1625}
1626
1627impl<'de> Deserialize<'de> for TargetPath {
1628    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
1629        let s: String = Deserialize::deserialize(de)?;
1630        TargetPath::new(s).map_err(|e| DeserializeError::custom(format!("{:?}", e)))
1631    }
1632}
1633
1634impl Borrow<str> for TargetPath {
1635    fn borrow(&self) -> &str {
1636        self.as_str()
1637    }
1638}
1639
1640/// Description of a target, used in verification.
1641#[derive(Debug, Clone, PartialEq, Eq)]
1642pub struct TargetDescription {
1643    length: u64,
1644    hashes: HashMap<HashAlgorithm, HashValue>,
1645    custom: HashMap<String, serde_json::Value>,
1646}
1647
1648impl TargetDescription {
1649    /// Create a new `TargetDescription`.
1650    ///
1651    /// Note: Creating this manually could lead to errors, and the `from_reader` method is
1652    /// preferred.
1653    pub fn new(
1654        length: u64,
1655        hashes: HashMap<HashAlgorithm, HashValue>,
1656        custom: HashMap<String, serde_json::Value>,
1657    ) -> Result<Self> {
1658        if hashes.is_empty() {
1659            return Err(Error::IllegalArgument(
1660                "Cannot have empty set of hashes".into(),
1661            ));
1662        }
1663
1664        Ok(TargetDescription {
1665            length,
1666            hashes,
1667            custom,
1668        })
1669    }
1670
1671    /// Read the from the given slice and calculate the length and hash values.
1672    ///
1673    /// ```
1674    /// # use data_encoding::BASE64URL;
1675    /// # use tuf::crypto::{HashAlgorithm,HashValue};
1676    /// # use tuf::metadata::TargetDescription;
1677    /// #
1678    /// let bytes: &[u8] = b"it was a pleasure to burn";
1679    ///
1680    /// let target_description = TargetDescription::from_slice(
1681    ///     bytes,
1682    ///     &[HashAlgorithm::Sha256, HashAlgorithm::Sha512],
1683    /// ).unwrap();
1684    ///
1685    /// let s = "Rd9zlbzrdWfeL7gnIEi05X-Yv2TCpy4qqZM1N72ZWQs=";
1686    /// let sha256 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1687    ///
1688    /// let s ="tuIxwKybYdvJpWuUj6dubvpwhkAozWB6hMJIRzqn2jOUdtDTBg381brV4K\
1689    ///     BU1zKP8GShoJuXEtCf5NkDTCEJgQ==";
1690    /// let sha512 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1691    ///
1692    /// assert_eq!(target_description.length(), bytes.len() as u64);
1693    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha256), Some(&sha256));
1694    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha512), Some(&sha512));
1695    /// ```
1696    pub fn from_slice(buf: &[u8], hash_algs: &[HashAlgorithm]) -> Result<Self> {
1697        Self::from_slice_with_custom(buf, hash_algs, HashMap::new())
1698    }
1699
1700    /// Read the from the given reader and custom metadata and calculate the length and hash
1701    /// values.
1702    ///
1703    /// ```
1704    /// # use data_encoding::BASE64URL;
1705    /// # use serde_json::Value;
1706    /// # use std::collections::HashMap;
1707    /// # use tuf::crypto::{HashAlgorithm,HashValue};
1708    /// # use tuf::metadata::TargetDescription;
1709    /// #
1710    /// let bytes: &[u8] = b"it was a pleasure to burn";
1711    ///
1712    /// let mut custom = HashMap::new();
1713    /// custom.insert("Hello".into(), "World".into());
1714    ///
1715    /// let target_description = TargetDescription::from_slice_with_custom(
1716    ///     bytes,
1717    ///     &[HashAlgorithm::Sha256, HashAlgorithm::Sha512],
1718    ///     custom,
1719    /// ).unwrap();
1720    ///
1721    /// let s = "Rd9zlbzrdWfeL7gnIEi05X-Yv2TCpy4qqZM1N72ZWQs=";
1722    /// let sha256 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1723    ///
1724    /// let s ="tuIxwKybYdvJpWuUj6dubvpwhkAozWB6hMJIRzqn2jOUdtDTBg381brV4K\
1725    ///     BU1zKP8GShoJuXEtCf5NkDTCEJgQ==";
1726    /// let sha512 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1727    ///
1728    /// assert_eq!(target_description.length(), bytes.len() as u64);
1729    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha256), Some(&sha256));
1730    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha512), Some(&sha512));
1731    /// assert_eq!(target_description.custom().get("Hello"), Some(&"World".into()));
1732    /// ```
1733    pub fn from_slice_with_custom(
1734        buf: &[u8],
1735        hash_algs: &[HashAlgorithm],
1736        custom: HashMap<String, serde_json::Value>,
1737    ) -> Result<Self> {
1738        let hashes = crypto::calculate_hashes_from_slice(buf, hash_algs)?;
1739        Ok(TargetDescription {
1740            length: buf.len() as u64,
1741            hashes,
1742            custom,
1743        })
1744    }
1745
1746    /// Read the from the given reader and calculate the length and hash values.
1747    ///
1748    /// ```
1749    /// # use data_encoding::BASE64URL;
1750    /// # use futures_executor::block_on;
1751    /// # use tuf::crypto::{HashAlgorithm,HashValue};
1752    /// # use tuf::metadata::TargetDescription;
1753    /// #
1754    /// # block_on(async {
1755    /// let bytes: &[u8] = b"it was a pleasure to burn";
1756    ///
1757    /// let target_description = TargetDescription::from_reader(
1758    ///     bytes,
1759    ///     &[HashAlgorithm::Sha256, HashAlgorithm::Sha512],
1760    /// ).await.unwrap();
1761    ///
1762    /// let s = "Rd9zlbzrdWfeL7gnIEi05X-Yv2TCpy4qqZM1N72ZWQs=";
1763    /// let sha256 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1764    ///
1765    /// let s ="tuIxwKybYdvJpWuUj6dubvpwhkAozWB6hMJIRzqn2jOUdtDTBg381brV4K\
1766    ///     BU1zKP8GShoJuXEtCf5NkDTCEJgQ==";
1767    /// let sha512 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1768    ///
1769    /// assert_eq!(target_description.length(), bytes.len() as u64);
1770    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha256), Some(&sha256));
1771    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha512), Some(&sha512));
1772    /// # })
1773    /// ```
1774    pub async fn from_reader<R>(read: R, hash_algs: &[HashAlgorithm]) -> Result<Self>
1775    where
1776        R: AsyncRead + Unpin,
1777    {
1778        Self::from_reader_with_custom(read, hash_algs, HashMap::new()).await
1779    }
1780
1781    /// Read the from the given reader and custom metadata and calculate the length and hash
1782    /// values.
1783    ///
1784    /// ```
1785    /// # use data_encoding::BASE64URL;
1786    /// # use futures_executor::block_on;
1787    /// # use serde_json::Value;
1788    /// # use std::collections::HashMap;
1789    /// # use tuf::crypto::{HashAlgorithm,HashValue};
1790    /// # use tuf::metadata::TargetDescription;
1791    /// #
1792    /// # block_on(async {
1793    /// let bytes: &[u8] = b"it was a pleasure to burn";
1794    ///
1795    /// let mut custom = HashMap::new();
1796    /// custom.insert("Hello".into(), "World".into());
1797    ///
1798    /// let target_description = TargetDescription::from_reader_with_custom(
1799    ///     bytes,
1800    ///     &[HashAlgorithm::Sha256, HashAlgorithm::Sha512],
1801    ///     custom,
1802    /// ).await.unwrap();
1803    ///
1804    /// let s = "Rd9zlbzrdWfeL7gnIEi05X-Yv2TCpy4qqZM1N72ZWQs=";
1805    /// let sha256 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1806    ///
1807    /// let s ="tuIxwKybYdvJpWuUj6dubvpwhkAozWB6hMJIRzqn2jOUdtDTBg381brV4K\
1808    ///     BU1zKP8GShoJuXEtCf5NkDTCEJgQ==";
1809    /// let sha512 = HashValue::new(BASE64URL.decode(s.as_bytes()).unwrap());
1810    ///
1811    /// assert_eq!(target_description.length(), bytes.len() as u64);
1812    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha256), Some(&sha256));
1813    /// assert_eq!(target_description.hashes().get(&HashAlgorithm::Sha512), Some(&sha512));
1814    /// assert_eq!(target_description.custom().get("Hello"), Some(&"World".into()));
1815    /// })
1816    /// ```
1817    pub async fn from_reader_with_custom<R>(
1818        read: R,
1819        hash_algs: &[HashAlgorithm],
1820        custom: HashMap<String, serde_json::Value>,
1821    ) -> Result<Self>
1822    where
1823        R: AsyncRead + Unpin,
1824    {
1825        let (length, hashes) = crypto::calculate_hashes_from_reader(read, hash_algs).await?;
1826        Ok(TargetDescription {
1827            length,
1828            hashes,
1829            custom,
1830        })
1831    }
1832
1833    /// The maximum length of the target.
1834    pub fn length(&self) -> u64 {
1835        self.length
1836    }
1837
1838    /// An immutable reference to the list of calculated hashes.
1839    pub fn hashes(&self) -> &HashMap<HashAlgorithm, HashValue> {
1840        &self.hashes
1841    }
1842
1843    /// An immutable reference to the custom metadata.
1844    pub fn custom(&self) -> &HashMap<String, serde_json::Value> {
1845        &self.custom
1846    }
1847}
1848
1849impl Serialize for TargetDescription {
1850    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
1851    where
1852        S: Serializer,
1853    {
1854        shims::TargetDescription::from(self).serialize(ser)
1855    }
1856}
1857
1858impl<'de> Deserialize<'de> for TargetDescription {
1859    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
1860        let intermediate: shims::TargetDescription = Deserialize::deserialize(de)?;
1861        intermediate
1862            .try_into()
1863            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
1864    }
1865}
1866
1867/// Metadata for the targets role.
1868#[derive(Debug, Clone, PartialEq, Eq)]
1869pub struct TargetsMetadata {
1870    version: u32,
1871    expires: DateTime<Utc>,
1872    targets: HashMap<TargetPath, TargetDescription>,
1873    delegations: Delegations,
1874    additional_fields: HashMap<String, serde_json::Value>,
1875}
1876
1877impl TargetsMetadata {
1878    /// Create new `TargetsMetadata`.
1879    pub fn new(
1880        version: u32,
1881        expires: DateTime<Utc>,
1882        targets: HashMap<TargetPath, TargetDescription>,
1883        delegations: Delegations,
1884        additional_fields: HashMap<String, serde_json::Value>,
1885    ) -> Result<Self> {
1886        if version < 1 {
1887            return Err(Error::MetadataVersionMustBeGreaterThanZero(
1888                MetadataPath::targets(),
1889            ));
1890        }
1891
1892        Ok(TargetsMetadata {
1893            version,
1894            expires,
1895            targets,
1896            delegations,
1897            additional_fields,
1898        })
1899    }
1900
1901    /// An immutable reference to the descriptions of targets.
1902    pub fn targets(&self) -> &HashMap<TargetPath, TargetDescription> {
1903        &self.targets
1904    }
1905
1906    /// An immutable reference to the optional delegations.
1907    pub fn delegations(&self) -> &Delegations {
1908        &self.delegations
1909    }
1910
1911    /// An immutable reference to any additional fields on the metadata.
1912    pub fn additional_fields(&self) -> &HashMap<String, serde_json::Value> {
1913        &self.additional_fields
1914    }
1915}
1916
1917impl Metadata for TargetsMetadata {
1918    const ROLE: Role = Role::Targets;
1919
1920    fn version(&self) -> u32 {
1921        self.version
1922    }
1923
1924    fn expires(&self) -> &DateTime<Utc> {
1925        &self.expires
1926    }
1927}
1928
1929impl Serialize for TargetsMetadata {
1930    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
1931    where
1932        S: Serializer,
1933    {
1934        shims::TargetsMetadata::from(self)
1935            .map_err(|e| SerializeError::custom(format!("{:?}", e)))?
1936            .serialize(ser)
1937    }
1938}
1939
1940impl<'de> Deserialize<'de> for TargetsMetadata {
1941    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
1942        let intermediate: shims::TargetsMetadata = Deserialize::deserialize(de)?;
1943        intermediate
1944            .try_into()
1945            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
1946    }
1947}
1948
1949/// Helper to construct `TargetsMetadata`.
1950pub struct TargetsMetadataBuilder {
1951    version: u32,
1952    expires: DateTime<Utc>,
1953    targets: HashMap<TargetPath, TargetDescription>,
1954    delegations: Option<Delegations>,
1955}
1956
1957impl TargetsMetadataBuilder {
1958    /// Create a new `TargetsMetadataBuilder`. It defaults to:
1959    ///
1960    /// * version: 1
1961    /// * expires: 90 days from the current time.
1962    pub fn new() -> Self {
1963        TargetsMetadataBuilder {
1964            version: 1,
1965            expires: Utc::now() + Duration::days(90),
1966            targets: HashMap::new(),
1967            delegations: None,
1968        }
1969    }
1970
1971    /// Set the version number for this metadata.
1972    pub fn version(mut self, version: u32) -> Self {
1973        self.version = version;
1974        self
1975    }
1976
1977    /// Set the time this metadata expires.
1978    pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
1979        self.expires = expires;
1980        self
1981    }
1982
1983    /// Add target to the target metadata.
1984    pub fn insert_target_from_slice(
1985        self,
1986        path: TargetPath,
1987        buf: &[u8],
1988        hash_algs: &[HashAlgorithm],
1989    ) -> Result<Self> {
1990        let description = TargetDescription::from_slice(buf, hash_algs)?;
1991        Ok(self.insert_target_description(path, description))
1992    }
1993
1994    /// Add target to the target metadata.
1995    pub async fn insert_target_from_reader<R>(
1996        self,
1997        path: TargetPath,
1998        read: R,
1999        hash_algs: &[HashAlgorithm],
2000    ) -> Result<Self>
2001    where
2002        R: AsyncRead + Unpin,
2003    {
2004        let description = TargetDescription::from_reader(read, hash_algs).await?;
2005        Ok(self.insert_target_description(path, description))
2006    }
2007
2008    /// Add `TargetDescription` to this target metadata target description.
2009    pub fn insert_target_description(
2010        mut self,
2011        path: TargetPath,
2012        description: TargetDescription,
2013    ) -> Self {
2014        self.targets.insert(path, description);
2015        self
2016    }
2017
2018    /// Add `Delegations` to this target metadata.
2019    pub fn delegations(mut self, delegations: Delegations) -> Self {
2020        self.delegations = Some(delegations);
2021        self
2022    }
2023
2024    /// Construct a new `TargetsMetadata`.
2025    pub fn build(self) -> Result<TargetsMetadata> {
2026        TargetsMetadata::new(
2027            self.version,
2028            self.expires,
2029            self.targets,
2030            self.delegations.unwrap_or_default(),
2031            Default::default(),
2032        )
2033    }
2034
2035    /// Construct a new `SignedMetadata<D, TargetsMetadata>`.
2036    pub fn signed<D>(
2037        self,
2038        private_key: &dyn PrivateKey,
2039    ) -> Result<SignedMetadata<D, TargetsMetadata>>
2040    where
2041        D: Pouf,
2042    {
2043        SignedMetadata::new(&self.build()?, private_key)
2044    }
2045}
2046
2047impl Default for TargetsMetadataBuilder {
2048    fn default() -> Self {
2049        TargetsMetadataBuilder::new()
2050    }
2051}
2052
2053/// Wrapper to described a collections of delegations.
2054#[derive(Debug, Clone, PartialEq, Eq, Default)]
2055pub struct Delegations {
2056    keys: HashMap<KeyId, PublicKey>,
2057    roles: Vec<Delegation>,
2058}
2059
2060impl Delegations {
2061    /// Return a [DelegationsBuilder].
2062    pub fn builder() -> DelegationsBuilder {
2063        DelegationsBuilder::new()
2064    }
2065
2066    // TODO check all keys are used
2067    // TODO check all roles have their ID in the set of keys
2068    /// Create a new `Delegations` wrapper from the given set of trusted keys and roles.
2069    pub fn new(keys: HashMap<KeyId, PublicKey>, roles: Vec<Delegation>) -> Result<Self> {
2070        if roles.len()
2071            != roles
2072                .iter()
2073                .map(|r| &r.name)
2074                .collect::<HashSet<&MetadataPath>>()
2075                .len()
2076        {
2077            return Err(Error::IllegalArgument(
2078                "Cannot have duplicated roles in delegations.".into(),
2079            ));
2080        }
2081
2082        Ok(Delegations { keys, roles })
2083    }
2084
2085    /// Return if this delegation is empty.
2086    pub fn is_empty(&self) -> bool {
2087        self.keys.is_empty() && self.roles.is_empty()
2088    }
2089
2090    /// An immutable reference to the keys used for this set of delegations.
2091    pub fn keys(&self) -> &HashMap<KeyId, PublicKey> {
2092        &self.keys
2093    }
2094
2095    /// An immutable reference to the delegated roles.
2096    pub fn roles(&self) -> &Vec<Delegation> {
2097        &self.roles
2098    }
2099}
2100
2101impl Serialize for Delegations {
2102    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
2103    where
2104        S: Serializer,
2105    {
2106        shims::Delegations::from(self).serialize(ser)
2107    }
2108}
2109
2110impl<'de> Deserialize<'de> for Delegations {
2111    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
2112        let intermediate: shims::Delegations = Deserialize::deserialize(de)?;
2113        intermediate
2114            .try_into()
2115            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
2116    }
2117}
2118
2119/// A builder for [Delegations].
2120#[derive(Default)]
2121pub struct DelegationsBuilder {
2122    keys: HashMap<KeyId, PublicKey>,
2123    roles: Vec<Delegation>,
2124    role_index: HashMap<MetadataPath, usize>,
2125}
2126
2127impl DelegationsBuilder {
2128    /// Create a new [DelegationsBuilder].
2129    pub fn new() -> Self {
2130        Self {
2131            keys: HashMap::new(),
2132            roles: vec![],
2133            role_index: HashMap::new(),
2134        }
2135    }
2136
2137    /// Include this key in the delegation [PublicKey] set.
2138    pub fn key(mut self, key: PublicKey) -> Self {
2139        self.keys.insert(key.key_id().clone(), key);
2140        self
2141    }
2142
2143    /// Add a [Delegation].
2144    pub fn role(mut self, delegation: Delegation) -> Self {
2145        // The delegation list is ordered and unique by role name, so check if we should overwrite
2146        // the old delegation.
2147        if let Some(idx) = self.role_index.get(&delegation.name) {
2148            self.roles[*idx] = delegation;
2149        } else {
2150            self.role_index
2151                .insert(delegation.name.clone(), self.roles.len());
2152
2153            self.roles.push(delegation);
2154        }
2155
2156        self
2157    }
2158
2159    /// Construct a new [Delegations].
2160    pub fn build(self) -> Result<Delegations> {
2161        Delegations::new(self.keys, self.roles)
2162    }
2163}
2164
2165/// A delegated targets role.
2166#[derive(Debug, Clone, PartialEq, Eq)]
2167pub struct Delegation {
2168    name: MetadataPath,
2169    terminating: bool,
2170    threshold: u32,
2171    key_ids: HashSet<KeyId>,
2172    paths: HashSet<TargetPath>,
2173}
2174
2175impl Delegation {
2176    /// Create a new [DelegationBuilder] for a delegation named `role`.
2177    pub fn builder(role: MetadataPath) -> DelegationBuilder {
2178        DelegationBuilder::new(role)
2179    }
2180
2181    /// Create a new delegation.
2182    pub fn new(
2183        name: MetadataPath,
2184        terminating: bool,
2185        threshold: u32,
2186        key_ids: HashSet<KeyId>,
2187        paths: HashSet<TargetPath>,
2188    ) -> Result<Self> {
2189        if key_ids.is_empty() {
2190            return Err(Error::IllegalArgument("Cannot have empty key IDs".into()));
2191        }
2192
2193        if paths.is_empty() {
2194            return Err(Error::IllegalArgument("Cannot have empty paths".into()));
2195        }
2196
2197        if threshold < 1 {
2198            return Err(Error::IllegalArgument("Cannot have threshold < 1".into()));
2199        }
2200
2201        if (key_ids.len() as u64) < u64::from(threshold) {
2202            return Err(Error::IllegalArgument(
2203                "Cannot have threshold less than number of keys".into(),
2204            ));
2205        }
2206
2207        Ok(Delegation {
2208            name,
2209            terminating,
2210            threshold,
2211            key_ids,
2212            paths,
2213        })
2214    }
2215
2216    /// An immutable reference to the delegations's metadata path (role).
2217    pub fn name(&self) -> &MetadataPath {
2218        &self.name
2219    }
2220
2221    /// Whether or not this delegation is terminating.
2222    pub fn terminating(&self) -> bool {
2223        self.terminating
2224    }
2225
2226    /// An immutable reference to the delegations's trusted key IDs.
2227    pub fn key_ids(&self) -> &HashSet<KeyId> {
2228        &self.key_ids
2229    }
2230
2231    /// The delegation's threshold.
2232    pub fn threshold(&self) -> u32 {
2233        self.threshold
2234    }
2235
2236    /// An immutable reference to the delegation's authorized paths.
2237    pub fn paths(&self) -> &HashSet<TargetPath> {
2238        &self.paths
2239    }
2240}
2241
2242impl Serialize for Delegation {
2243    fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
2244    where
2245        S: Serializer,
2246    {
2247        shims::Delegation::from(self).serialize(ser)
2248    }
2249}
2250
2251impl<'de> Deserialize<'de> for Delegation {
2252    fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
2253        let intermediate: shims::Delegation = Deserialize::deserialize(de)?;
2254        intermediate
2255            .try_into()
2256            .map_err(|e| DeserializeError::custom(format!("{:?}", e)))
2257    }
2258}
2259
2260/// A builder for [Delegation].
2261pub struct DelegationBuilder {
2262    role: MetadataPath,
2263    terminating: bool,
2264    threshold: u32,
2265    key_ids: HashSet<KeyId>,
2266    paths: HashSet<TargetPath>,
2267}
2268
2269impl DelegationBuilder {
2270    /// Create a new [DelegationBuilder] for a delegation named `role`.
2271    pub fn new(role: MetadataPath) -> Self {
2272        Self {
2273            role,
2274            terminating: false,
2275            threshold: 1,
2276            key_ids: HashSet::new(),
2277            paths: HashSet::new(),
2278        }
2279    }
2280
2281    /// The threshold number of signatures required for the delegation to be trusted.
2282    pub fn threshold(mut self, threshold: u32) -> Self {
2283        self.threshold = threshold;
2284        self
2285    }
2286
2287    /// This delegation can be signed by this [PublicKey].
2288    pub fn key(mut self, key: &PublicKey) -> Self {
2289        self.key_ids.insert(key.key_id().clone());
2290        self
2291    }
2292
2293    /// This delegation can be signed by this [KeyId].
2294    pub fn key_id(mut self, key_id: KeyId) -> Self {
2295        self.key_ids.insert(key_id);
2296        self
2297    }
2298
2299    /// Delegate `path` to this delegation.
2300    pub fn delegate_path(mut self, path: TargetPath) -> Self {
2301        self.paths.insert(path);
2302        self
2303    }
2304
2305    /// Construct the [Delegation].
2306    pub fn build(self) -> Result<Delegation> {
2307        Delegation::new(
2308            self.role,
2309            self.terminating,
2310            self.threshold,
2311            self.key_ids,
2312            self.paths,
2313        )
2314    }
2315}
2316
2317#[cfg(test)]
2318mod test {
2319    use super::*;
2320    use crate::crypto::Ed25519PrivateKey;
2321    use crate::pouf::Pouf1;
2322    use crate::verify::verify_signatures;
2323    use assert_matches::assert_matches;
2324    use chrono::prelude::*;
2325    use futures_executor::block_on;
2326    use maplit::{hashmap, hashset};
2327    use pretty_assertions::assert_eq;
2328    use serde_json::json;
2329    use std::str::FromStr;
2330
2331    const ED25519_1_PK8: &[u8] = include_bytes!("../tests/ed25519/ed25519-1.pk8.der");
2332    const ED25519_2_PK8: &[u8] = include_bytes!("../tests/ed25519/ed25519-2.pk8.der");
2333    const ED25519_3_PK8: &[u8] = include_bytes!("../tests/ed25519/ed25519-3.pk8.der");
2334    const ED25519_4_PK8: &[u8] = include_bytes!("../tests/ed25519/ed25519-4.pk8.der");
2335
2336    #[test]
2337    fn no_pardir_in_target_path() {
2338        let bad_paths = &[
2339            "..",
2340            "../some/path",
2341            "../some/path/",
2342            "some/../path",
2343            "some/../path/..",
2344        ];
2345
2346        for path in bad_paths.iter() {
2347            assert!(safe_path(path).is_err());
2348            assert!(TargetPath::new(path.to_string()).is_err());
2349            assert!(MetadataPath::new(path.to_string()).is_err());
2350            assert!(TargetPath::new(path.to_string()).is_err());
2351        }
2352    }
2353
2354    #[test]
2355    fn allow_asterisk_in_target_path() {
2356        let good_paths = &[
2357            "*",
2358            "*/some/path",
2359            "*/some/path/",
2360            "some/*/path",
2361            "some/*/path/*",
2362        ];
2363
2364        for path in good_paths.iter() {
2365            assert!(safe_path(path).is_ok());
2366            assert!(TargetPath::new(path.to_string()).is_ok());
2367            assert!(MetadataPath::new(path.to_string()).is_ok());
2368        }
2369    }
2370
2371    #[test]
2372    fn path_matches_chain() {
2373        let test_cases: &[(bool, &str, &[&[&str]])] = &[
2374            // simplest case
2375            (true, "foo", &[&["foo"]]),
2376            // direct delegation case
2377            (true, "foo", &[&["foo"], &["foo"]]),
2378            // is a dir
2379            (false, "foo", &[&["foo/"]]),
2380            // target not in last position
2381            (false, "foo", &[&["foo"], &["bar"]]),
2382            // target nested
2383            (true, "foo/bar", &[&["foo/"], &["foo/bar"]]),
2384            // target illegally nested
2385            (false, "foo/bar", &[&["baz/"], &["foo/bar"]]),
2386            // target illegally deeply nested
2387            (
2388                false,
2389                "foo/bar/baz",
2390                &[&["foo/"], &["foo/quux/"], &["foo/bar/baz"]],
2391            ),
2392            // empty
2393            (false, "foo", &[&[]]),
2394            // empty 2
2395            (false, "foo", &[&[], &["foo"]]),
2396            // empty 3
2397            (false, "foo", &[&["foo"], &[]]),
2398        ];
2399
2400        for case in test_cases {
2401            let expected = case.0;
2402            let target = TargetPath::new(case.1).unwrap();
2403            let parents = case
2404                .2
2405                .iter()
2406                .map(|group| {
2407                    group
2408                        .iter()
2409                        .map(|p| TargetPath::new(p.to_string()).unwrap())
2410                        .collect::<HashSet<_>>()
2411                })
2412                .collect::<Vec<_>>();
2413            println!(
2414                "CASE: expect: {} path: {:?} parents: {:?}",
2415                expected, target, parents
2416            );
2417            assert_eq!(target.matches_chain(&parents), expected);
2418        }
2419    }
2420
2421    #[test]
2422    fn serde_target_path() {
2423        let s = "foo/bar";
2424        let t = serde_json::from_str::<TargetPath>(&format!("\"{}\"", s)).unwrap();
2425        assert_eq!(t.to_string().as_str(), s);
2426        assert_eq!(serde_json::to_value(t).unwrap(), json!("foo/bar"));
2427    }
2428
2429    #[test]
2430    fn serde_metadata_path() {
2431        let s = "foo/bar";
2432        let m = serde_json::from_str::<MetadataPath>(&format!("\"{}\"", s)).unwrap();
2433        assert_eq!(m.to_string().as_str(), s);
2434        assert_eq!(serde_json::to_value(m).unwrap(), json!("foo/bar"));
2435    }
2436
2437    #[test]
2438    fn serde_target_description() {
2439        let s: &[u8] = b"from water does all life begin";
2440        let description = TargetDescription::from_slice(s, &[HashAlgorithm::Sha256]).unwrap();
2441        let jsn_str = serde_json::to_string(&description).unwrap();
2442        let jsn = json!({
2443            "length": 30,
2444            "hashes": {
2445                "sha256": "fc5d745c712bc86ea9a31264dac0c956eeb53857f677eed05829\
2446                    bb71013cae18",
2447            },
2448        });
2449        let parsed_str: TargetDescription = serde_json::from_str(&jsn_str).unwrap();
2450        let parsed_jsn: TargetDescription = serde_json::from_value(jsn).unwrap();
2451        assert_eq!(parsed_str, parsed_jsn);
2452    }
2453
2454    #[test]
2455    fn serde_role_definition() {
2456        // keyid ordering must be preserved.
2457        let keyids = hashset![
2458            KeyId::from_str("40e35e8f6003ab90d104710cf88901edab931597401f91c19eeb366060ab3d53")
2459                .unwrap(),
2460            KeyId::from_str("01892c662c8cd79fab20edec21de1dcb8b75d9353103face7fe086ff5c0098e4")
2461                .unwrap(),
2462            KeyId::from_str("4750eaf6878740780d6f97b12dbad079fb012bec88c78de2c380add56d3f51db")
2463                .unwrap(),
2464        ];
2465        let role_def = RoleDefinition::new(3, keyids).unwrap();
2466        let jsn = json!({
2467            "threshold": 3,
2468            "keyids": [
2469                "01892c662c8cd79fab20edec21de1dcb8b75d9353103face7fe086ff5c0098e4",
2470                "40e35e8f6003ab90d104710cf88901edab931597401f91c19eeb366060ab3d53",
2471                "4750eaf6878740780d6f97b12dbad079fb012bec88c78de2c380add56d3f51db",
2472            ],
2473        });
2474        let encoded = serde_json::to_value(&role_def).unwrap();
2475        assert_eq!(encoded, jsn);
2476        let decoded: RoleDefinition<RootMetadata> = serde_json::from_value(encoded).unwrap();
2477        assert_eq!(decoded, role_def);
2478    }
2479
2480    #[test]
2481    fn serde_invalid_role_definitions() {
2482        let jsn = json!({
2483            "threshold": 0,
2484            "keyids": [
2485                "01892c662c8cd79fab20edec21de1dcb8b75d9353103face7fe086ff5c0098e4",
2486                "4750eaf6878740780d6f97b12dbad079fb012bec88c78de2c380add56d3f51db",
2487            ],
2488        });
2489        assert!(serde_json::from_value::<RoleDefinition<RootMetadata>>(jsn).is_err());
2490
2491        let jsn = json!({
2492            "threshold": -1,
2493            "keyids": [
2494                "01892c662c8cd79fab20edec21de1dcb8b75d9353103face7fe086ff5c0098e4",
2495                "4750eaf6878740780d6f97b12dbad079fb012bec88c78de2c380add56d3f51db",
2496            ],
2497        });
2498        assert!(serde_json::from_value::<RoleDefinition<RootMetadata>>(jsn).is_err());
2499    }
2500
2501    #[test]
2502    fn serde_root_metadata() {
2503        let root_key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
2504        let snapshot_key = Ed25519PrivateKey::from_pkcs8(ED25519_2_PK8).unwrap();
2505        let targets_key = Ed25519PrivateKey::from_pkcs8(ED25519_3_PK8).unwrap();
2506        let timestamp_key = Ed25519PrivateKey::from_pkcs8(ED25519_4_PK8).unwrap();
2507
2508        let root = RootMetadataBuilder::new()
2509            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
2510            .root_key(root_key.public().clone())
2511            .snapshot_key(snapshot_key.public().clone())
2512            .targets_key(targets_key.public().clone())
2513            .timestamp_key(timestamp_key.public().clone())
2514            .build()
2515            .unwrap();
2516
2517        let jsn = json!({
2518            "_type": "root",
2519            "spec_version": "1.0",
2520            "version": 1,
2521            "expires": "2017-01-01T00:00:00Z",
2522            "consistent_snapshot": true,
2523            "keys": {
2524                "09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1": {
2525                    "keytype": "ed25519",
2526                    "scheme": "ed25519",
2527                    "keyid_hash_algorithms": ["sha256", "sha512"],
2528                    "keyval": {
2529                        "public": "1410ae3053aa70bbfa98428a879d64d3002a3578f7dfaaeb1cb0764e860f7e0b",
2530                    },
2531                },
2532                "40e35e8f6003ab90d104710cf88901edab931597401f91c19eeb366060ab3d53": {
2533                    "keytype": "ed25519",
2534                    "scheme": "ed25519",
2535                    "keyid_hash_algorithms": ["sha256", "sha512"],
2536                    "keyval": {
2537                        "public": "166376c90a7f717d027056272f361c252fb050bed1a067ff2089a0302fbab73d",
2538                    },
2539                },
2540                "a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a": {
2541                    "keytype": "ed25519",
2542                    "scheme": "ed25519",
2543                    "keyid_hash_algorithms": ["sha256", "sha512"],
2544                    "keyval": {
2545                        "public": "eb8ac26b5c9ef0279e3be3e82262a93bce16fe58ee422500d38caf461c65a3b6",
2546                    },
2547                },
2548                "fd7b7741686fa44903f1e4b61d7db869939f402b4acedc044767922c7d309983": {
2549                    "keytype": "ed25519",
2550                    "scheme": "ed25519",
2551                    "keyid_hash_algorithms": ["sha256", "sha512"],
2552                    "keyval": {
2553                        "public": "68d9ecb387371005a8eb8e60105305c34356a8fcd859d7fef3cc228bf2b2b3b2",
2554                    },
2555                }
2556            },
2557            "roles": {
2558                "root": {
2559                    "threshold": 1,
2560                    "keyids": ["a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a"],
2561                },
2562                "snapshot": {
2563                    "threshold": 1,
2564                    "keyids": ["fd7b7741686fa44903f1e4b61d7db869939f402b4acedc044767922c7d309983"],
2565                },
2566                "targets": {
2567                    "threshold": 1,
2568                    "keyids": ["40e35e8f6003ab90d104710cf88901edab931597401f91c19eeb366060ab3d53"],
2569                },
2570                "timestamp": {
2571                    "threshold": 1,
2572                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"],
2573                },
2574            },
2575        });
2576
2577        let encoded = serde_json::to_value(&root).unwrap();
2578        assert_eq!(encoded, jsn);
2579        let decoded: RootMetadata = serde_json::from_value(encoded).unwrap();
2580        assert_eq!(decoded, root);
2581    }
2582
2583    #[test]
2584    fn serde_root_metadata_additional_fields() {
2585        let jsn = json!({
2586            "_type": "root",
2587            "spec_version": "1.0",
2588            "version": 1,
2589            "expires": "2017-01-01T00:00:00Z",
2590            "consistent_snapshot": true,
2591            "keys": {
2592                "09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1": {
2593                    "keytype": "ed25519",
2594                    "scheme": "ed25519",
2595                    "keyid_hash_algorithms": ["sha256", "sha512"],
2596                    "keyval": {
2597                        "public": "1410ae3053aa70bbfa98428a879d64d3002a3578f7dfaaeb1cb0764e860f7e0b",
2598                    },
2599                },
2600            },
2601            "roles": {
2602                "root": {
2603                    "threshold": 1,
2604                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"],
2605                },
2606                "snapshot": {
2607                    "threshold": 1,
2608                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"],
2609                },
2610                "targets": {
2611                    "threshold": 1,
2612                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"],
2613                },
2614                "timestamp": {
2615                    "threshold": 1,
2616                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"],
2617                },
2618            },
2619            // additional_fields
2620            "custom": {
2621                "foo": 42,
2622                "bar": "baz",
2623            },
2624            "quux": true,
2625        });
2626
2627        let root: RootMetadata = serde_json::from_value(jsn.clone()).unwrap();
2628        assert_eq!(
2629            root.additional_fields()["custom"],
2630            json!({"foo": 42, "bar": "baz"})
2631        );
2632        assert_eq!(root.additional_fields()["quux"], json!(true));
2633
2634        // make sure additional_fields are passed through serialization as well
2635        assert_eq!(jsn, serde_json::to_value(&root).unwrap());
2636    }
2637
2638    fn jsn_root_metadata_without_keyid_hash_algos() -> serde_json::Value {
2639        json!({
2640            "_type": "root",
2641            "spec_version": "1.0",
2642            "version": 1,
2643            "expires": "2017-01-01T00:00:00Z",
2644            "consistent_snapshot": false,
2645            "keys": {
2646                "12435b260b6172bd750aeb102f54a347c56b109e0524ab1f144593c07af66356": {
2647                    "keytype": "ed25519",
2648                    "scheme": "ed25519",
2649                    "keyval": {
2650                        "public": "68d9ecb387371005a8eb8e60105305c34356a8fcd859d7fef3cc228bf2b2b3b2",
2651                    },
2652                },
2653                "3af6b427c05274532231760f39d81212fdf8ac1a9f8fddf12722623ccec02fec": {
2654                    "keytype": "ed25519",
2655                    "scheme": "ed25519",
2656                    "keyval": {
2657                        "public": "1410ae3053aa70bbfa98428a879d64d3002a3578f7dfaaeb1cb0764e860f7e0b",
2658                    },
2659                },
2660                "b9c336828063cf4fe5348e9fe2d86827c7b3104a76b1f4484a56bbef1ef08cfb": {
2661                    "keytype": "ed25519",
2662                    "scheme": "ed25519",
2663                    "keyval": {
2664                        "public": "166376c90a7f717d027056272f361c252fb050bed1a067ff2089a0302fbab73d",
2665                    },
2666                },
2667                "e0294a3f17cc8563c3ed5fceb3bd8d3f6bfeeaca499b5c9572729ae015566554": {
2668                    "keytype": "ed25519",
2669                    "scheme": "ed25519",
2670                    "keyval": {
2671                        "public": "eb8ac26b5c9ef0279e3be3e82262a93bce16fe58ee422500d38caf461c65a3b6",
2672                    },
2673                }
2674            },
2675            "roles": {
2676                "root": {
2677                    "threshold": 1,
2678                    "keyids": ["e0294a3f17cc8563c3ed5fceb3bd8d3f6bfeeaca499b5c9572729ae015566554"],
2679                },
2680                "snapshot": {
2681                    "threshold": 1,
2682                    "keyids": ["12435b260b6172bd750aeb102f54a347c56b109e0524ab1f144593c07af66356"],
2683                },
2684                "targets": {
2685                    "threshold": 1,
2686                    "keyids": ["b9c336828063cf4fe5348e9fe2d86827c7b3104a76b1f4484a56bbef1ef08cfb"],
2687                },
2688                "timestamp": {
2689                    "threshold": 1,
2690                    "keyids": ["3af6b427c05274532231760f39d81212fdf8ac1a9f8fddf12722623ccec02fec"],
2691                },
2692            },
2693        })
2694    }
2695
2696    #[test]
2697    fn de_ser_root_metadata_without_keyid_hash_algorithms() {
2698        let jsn = jsn_root_metadata_without_keyid_hash_algos();
2699        let decoded: RootMetadata = serde_json::from_value(jsn.clone()).unwrap();
2700        let encoded = serde_json::to_value(decoded).unwrap();
2701
2702        assert_eq!(jsn, encoded);
2703    }
2704
2705    #[test]
2706    fn de_ser_root_metadata_wrong_key_id() {
2707        let jsn = jsn_root_metadata_without_keyid_hash_algos();
2708        let mut jsn_str = str::from_utf8(&Pouf1::canonicalize(&jsn).unwrap())
2709            .unwrap()
2710            .to_owned();
2711        // Replace the key id to something else.
2712        jsn_str = jsn_str.replace(
2713            "12435b260b6172bd750aeb102f54a347c56b109e0524ab1f144593c07af66356",
2714            "00435b260b6172bd750aeb102f54a347c56b109e0524ab1f144593c07af66356",
2715        );
2716        let decoded: RootMetadata = serde_json::from_str(&jsn_str).unwrap();
2717        assert_eq!(3, decoded.keys.len());
2718    }
2719
2720    #[test]
2721    fn sign_and_verify_root_metadata() {
2722        let jsn = jsn_root_metadata_without_keyid_hash_algos();
2723        let root_key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
2724        let decoded: RootMetadata = serde_json::from_value(jsn).unwrap();
2725
2726        let signed: SignedMetadata<crate::pouf::pouf1::Pouf1, _> =
2727            SignedMetadata::new(&decoded, &root_key).unwrap();
2728        let raw_root = signed.to_raw().unwrap();
2729
2730        assert_matches!(
2731            verify_signatures(
2732                &MetadataPath::root(),
2733                &raw_root,
2734                1,
2735                &[root_key.public().clone()]
2736            ),
2737            Ok(_)
2738        );
2739    }
2740
2741    #[test]
2742    fn verify_signed_serialized_root_metadata() {
2743        let jsn = json!({
2744            "signatures": [{
2745                "keyid": "a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a",
2746                "sig": "c4ba838e0d3f783716393a4d691f568f840733ff488bb79ac68287e97e0b31d63fcef392dbc978e878c2103ba231905af634cc651d6f0e63a35782d051ac6e00"
2747            }],
2748            "signed": jsn_root_metadata_without_keyid_hash_algos()
2749        });
2750        let root_key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
2751        let decoded: SignedMetadata<crate::pouf::pouf1::Pouf1, RootMetadata> =
2752            serde_json::from_value(jsn).unwrap();
2753        let raw_root = decoded.to_raw().unwrap();
2754
2755        assert_matches!(
2756            verify_signatures(
2757                &MetadataPath::root(),
2758                &raw_root,
2759                1,
2760                &[root_key.public().clone()]
2761            ),
2762            Ok(_)
2763        );
2764    }
2765
2766    #[test]
2767    fn verify_signed_serialized_root_metadata_with_duplicate_sig() {
2768        let jsn = json!({
2769            "signatures": [{
2770                "keyid": "a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a",
2771                "sig": "c4ba838e0d3f783716393a4d691f568f840733ff488bb79ac68287e97e0b31d63fcef392dbc978e878c2103ba231905af634cc651d6f0e63a35782d051ac6e00"
2772            },
2773            {
2774                "keyid": "a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a",
2775                "sig": "c4ba838e0d3f783716393a4d691f568f840733ff488bb79ac68287e97e0b31d63fcef392dbc978e878c2103ba231905af634cc651d6f0e63a35782d051ac6e00"
2776            }],
2777            "signed": jsn_root_metadata_without_keyid_hash_algos()
2778        });
2779        let root_key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
2780        let decoded: SignedMetadata<crate::pouf::pouf1::Pouf1, RootMetadata> =
2781            serde_json::from_value(jsn).unwrap();
2782        let raw_root = decoded.to_raw().unwrap();
2783        assert_matches!(
2784            verify_signatures(&MetadataPath::root(), &raw_root, 2, &[root_key.public().clone()]),
2785            Err(Error::MetadataMissingSignatures {
2786                role,
2787                number_of_valid_signatures: 1,
2788                threshold: 2,
2789            })
2790            if role == MetadataPath::root()
2791        );
2792        assert_matches!(
2793            verify_signatures(
2794                &MetadataPath::root(),
2795                &raw_root,
2796                1,
2797                &[root_key.public().clone()]
2798            ),
2799            Ok(_)
2800        );
2801    }
2802
2803    fn verify_signature_with_unknown_fields<M>(mut metadata: serde_json::Value)
2804    where
2805        M: Metadata,
2806    {
2807        let key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
2808        let public_keys = vec![key.public().clone()];
2809
2810        let mut standard = SignedMetadataBuilder::<Pouf1, M>::from_raw_metadata(metadata.clone())
2811            .unwrap()
2812            .sign(&key)
2813            .unwrap()
2814            .build()
2815            .to_raw()
2816            .unwrap()
2817            .parse_untrusted()
2818            .unwrap();
2819
2820        metadata.as_object_mut().unwrap().insert(
2821            "custom".into(),
2822            json!({
2823                "metadata": ["please", "sign", "me"],
2824                "this-too": 42,
2825            }),
2826        );
2827        let mut custom = SignedMetadataBuilder::<Pouf1, M>::from_raw_metadata(metadata)
2828            .unwrap()
2829            .sign(&key)
2830            .unwrap()
2831            .build()
2832            .to_raw()
2833            .unwrap()
2834            .parse_untrusted()
2835            .unwrap();
2836
2837        // Ensure the signatures are valid as-is.
2838        assert_matches!(
2839            verify_signatures(
2840                &M::ROLE.into(),
2841                &standard.to_raw().unwrap(),
2842                1,
2843                &public_keys
2844            ),
2845            Ok(_)
2846        );
2847        assert_matches!(
2848            verify_signatures(
2849                &M::ROLE.into(),
2850                &custom.to_raw().unwrap(),
2851                1,
2852                std::iter::once(key.public())
2853            ),
2854            Ok(_)
2855        );
2856
2857        // But not if the metadata was signed with custom fields and they are now missing or
2858        // unexpected new fields appear.
2859        std::mem::swap(&mut standard.metadata, &mut custom.metadata);
2860        assert_matches!(
2861            verify_signatures(
2862                &M::ROLE.into(),
2863                &standard.to_raw().unwrap(),
2864                1,
2865                std::iter::once(key.public())
2866            ),
2867            Err(Error::MetadataMissingSignatures { role, number_of_valid_signatures: 0, threshold: 1 })
2868            if role == M::ROLE.into()
2869        );
2870        assert_matches!(
2871            verify_signatures(
2872                &M::ROLE.into(),
2873                &custom.to_raw().unwrap(),
2874                1,
2875                std::iter::once(key.public())
2876            ),
2877            Err(Error::MetadataMissingSignatures { role, number_of_valid_signatures: 0, threshold: 1 })
2878            if role == M::ROLE.into()
2879        );
2880    }
2881
2882    #[test]
2883    fn unknown_fields_included_in_root_metadata_signature() {
2884        verify_signature_with_unknown_fields::<RootMetadata>(
2885            jsn_root_metadata_without_keyid_hash_algos(),
2886        );
2887    }
2888
2889    #[test]
2890    fn unknown_fields_included_in_timestamp_metadata_signature() {
2891        verify_signature_with_unknown_fields::<TimestampMetadata>(make_timestamp());
2892    }
2893
2894    #[test]
2895    fn unknown_fields_included_in_snapshot_metadata_signature() {
2896        verify_signature_with_unknown_fields::<SnapshotMetadata>(make_snapshot());
2897    }
2898
2899    #[test]
2900    fn unknown_fields_included_in_targets_metadata_signature() {
2901        verify_signature_with_unknown_fields::<TargetsMetadata>(make_targets());
2902    }
2903
2904    #[test]
2905    fn serde_timestamp_metadata() {
2906        let description = MetadataDescription::new(
2907            1,
2908            Some(100),
2909            hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
2910        )
2911        .unwrap();
2912
2913        let timestamp = TimestampMetadataBuilder::from_metadata_description(description)
2914            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
2915            .build()
2916            .unwrap();
2917
2918        let jsn = json!({
2919            "_type": "timestamp",
2920            "spec_version": "1.0",
2921            "version": 1,
2922            "expires": "2017-01-01T00:00:00Z",
2923            "meta": {
2924                "snapshot.json": {
2925                    "version": 1,
2926                    "length": 100,
2927                    "hashes": {
2928                        "sha256": "",
2929                    },
2930                },
2931            }
2932        });
2933
2934        let encoded = serde_json::to_value(&timestamp).unwrap();
2935        assert_eq!(encoded, jsn);
2936        let decoded: TimestampMetadata = serde_json::from_value(encoded).unwrap();
2937        assert_eq!(decoded, timestamp);
2938    }
2939
2940    #[test]
2941    fn serde_timestamp_metadata_additional_fields() {
2942        let jsn = json!({
2943            "_type": "timestamp",
2944            "spec_version": "1.0",
2945            "version": 1,
2946            "expires": "2017-01-01T00:00:00Z",
2947            "meta": {
2948                "snapshot.json": {
2949                    "version": 1,
2950                    "length": 100,
2951                    "hashes": {
2952                        "sha256": "",
2953                    },
2954                },
2955            },
2956            // additional_fields
2957            "custom": {
2958                "foo": 42,
2959                "bar": "baz",
2960            },
2961            "quux": true,
2962        });
2963
2964        let timestamp: TimestampMetadata = serde_json::from_value(jsn.clone()).unwrap();
2965        assert_eq!(
2966            timestamp.additional_fields()["custom"],
2967            json!({"foo": 42, "bar": "baz"})
2968        );
2969        assert_eq!(timestamp.additional_fields()["quux"], json!(true));
2970
2971        // make sure additional_fields are passed through serialization as well
2972        assert_eq!(jsn, serde_json::to_value(&timestamp).unwrap());
2973    }
2974
2975    // Deserialize timestamp metadata with optional length and hashes
2976    #[test]
2977    fn serde_timestamp_metadata_without_length_and_hashes() {
2978        let description = MetadataDescription::new(1, None, HashMap::new()).unwrap();
2979
2980        let timestamp = TimestampMetadataBuilder::from_metadata_description(description)
2981            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
2982            .build()
2983            .unwrap();
2984
2985        let jsn = json!({
2986            "_type": "timestamp",
2987            "spec_version": "1.0",
2988            "version": 1,
2989            "expires": "2017-01-01T00:00:00Z",
2990            "meta": {
2991                "snapshot.json": {
2992                    "version": 1
2993                },
2994            },
2995        });
2996
2997        let encoded = serde_json::to_value(&timestamp).unwrap();
2998        assert_eq!(encoded, jsn);
2999        let decoded: TimestampMetadata = serde_json::from_value(encoded).unwrap();
3000        assert_eq!(decoded, timestamp);
3001    }
3002
3003    #[test]
3004    fn serde_timestamp_metadata_missing_snapshot() {
3005        let jsn = json!({
3006            "_type": "timestamp",
3007            "spec_version": "1.0",
3008            "version": 1,
3009            "expires": "2017-01-01T00:00:00Z",
3010            "meta": {}
3011        });
3012
3013        assert_matches!(
3014            serde_json::from_value::<TimestampMetadata>(jsn),
3015            Err(ref err) if err.to_string() == "missing field `snapshot.json`"
3016        );
3017    }
3018
3019    #[test]
3020    fn serde_timestamp_metadata_extra_metadata() {
3021        let jsn = json!({
3022            "_type": "timestamp",
3023            "spec_version": "1.0",
3024            "version": 1,
3025            "expires": "2017-01-01T00:00:00Z",
3026            "meta": {
3027                "snapshot.json": {
3028                    "version": 1,
3029                    "length": 100,
3030                    "hashes": {
3031                        "sha256": "",
3032                    },
3033                },
3034                "targets.json": {
3035                    "version": 1,
3036                    "length": 100,
3037                    "hashes": {
3038                        "sha256": "",
3039                    },
3040                },
3041            }
3042        });
3043
3044        assert_matches!(
3045            serde_json::from_value::<TimestampMetadata>(jsn),
3046            Err(ref err) if err.to_string() ==
3047            "unknown field `targets.json`, expected `snapshot.json`"
3048        );
3049    }
3050
3051    #[test]
3052    fn serde_snapshot_metadata() {
3053        let snapshot = SnapshotMetadataBuilder::new()
3054            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
3055            .insert_metadata_description(
3056                MetadataPath::new("targets").unwrap(),
3057                MetadataDescription::new(
3058                    1,
3059                    Some(100),
3060                    hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
3061                )
3062                .unwrap(),
3063            )
3064            .build()
3065            .unwrap();
3066
3067        let jsn = json!({
3068            "_type": "snapshot",
3069            "spec_version": "1.0",
3070            "version": 1,
3071            "expires": "2017-01-01T00:00:00Z",
3072            "meta": {
3073                "targets.json": {
3074                    "version": 1,
3075                    "length": 100,
3076                    "hashes": {
3077                        "sha256": "",
3078                    },
3079                },
3080            },
3081        });
3082
3083        let encoded = serde_json::to_value(&snapshot).unwrap();
3084        assert_eq!(encoded, jsn);
3085        let decoded: SnapshotMetadata = serde_json::from_value(encoded).unwrap();
3086        assert_eq!(decoded, snapshot);
3087    }
3088
3089    #[test]
3090    fn serde_snapshot_metadata_additional_fields() {
3091        let jsn = json!({
3092            "_type": "snapshot",
3093            "spec_version": "1.0",
3094            "version": 1,
3095            "expires": "2017-01-01T00:00:00Z",
3096            "meta": {
3097                "targets.json": {
3098                    "version": 1,
3099                    "length": 100,
3100                    "hashes": {
3101                        "sha256": "",
3102                    },
3103                },
3104            },
3105            // additional_fields
3106            "custom": {
3107                "foo": 42,
3108                "bar": "baz",
3109            },
3110            "quux": true,
3111        });
3112
3113        let snapshot: SnapshotMetadata = serde_json::from_value(jsn.clone()).unwrap();
3114        assert_eq!(
3115            snapshot.additional_fields()["custom"],
3116            json!({"foo": 42, "bar": "baz"})
3117        );
3118        assert_eq!(snapshot.additional_fields()["quux"], json!(true));
3119
3120        // make sure additional_fields are passed through serialization as well
3121        assert_eq!(jsn, serde_json::to_value(&snapshot).unwrap());
3122    }
3123
3124    // Deserialize snapshot metadata with optional length and hashes
3125    #[test]
3126    fn serde_snapshot_optional_length_and_hashes() {
3127        let snapshot = SnapshotMetadataBuilder::new()
3128            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
3129            .insert_metadata_description(
3130                MetadataPath::new("targets").unwrap(),
3131                MetadataDescription::new(1, None, HashMap::new()).unwrap(),
3132            )
3133            .build()
3134            .unwrap();
3135
3136        let jsn = json!({
3137            "_type": "snapshot",
3138            "spec_version": "1.0",
3139            "version": 1,
3140            "expires": "2017-01-01T00:00:00Z",
3141            "meta": {
3142                "targets.json": {
3143                    "version": 1,
3144                },
3145            },
3146        });
3147
3148        let encoded = serde_json::to_value(&snapshot).unwrap();
3149        assert_eq!(encoded, jsn);
3150        let decoded: SnapshotMetadata = serde_json::from_value(encoded).unwrap();
3151        assert_eq!(decoded, snapshot);
3152    }
3153
3154    #[test]
3155    fn serde_targets_metadata() {
3156        block_on(async {
3157            let targets = TargetsMetadataBuilder::new()
3158                .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
3159                .insert_target_from_slice(
3160                    TargetPath::new("insert-target-from-slice").unwrap(),
3161                    &b"foo"[..],
3162                    &[HashAlgorithm::Sha256],
3163                )
3164                .unwrap()
3165                .insert_target_from_reader(
3166                    TargetPath::new("insert-target-from-reader").unwrap(),
3167                    &b"foo"[..],
3168                    &[HashAlgorithm::Sha256],
3169                )
3170                .await
3171                .unwrap()
3172                .insert_target_description(
3173                    TargetPath::new("insert-target-description-from-slice-with-custom").unwrap(),
3174                    TargetDescription::from_slice_with_custom(
3175                        &b"foo"[..],
3176                        &[HashAlgorithm::Sha256],
3177                        HashMap::new(),
3178                    )
3179                    .unwrap(),
3180                )
3181                .insert_target_description(
3182                    TargetPath::new("insert-target-description-from-reader-with-custom").unwrap(),
3183                    TargetDescription::from_reader_with_custom(
3184                        &b"foo"[..],
3185                        &[HashAlgorithm::Sha256],
3186                        hashmap! {
3187                            "foo".into() => 1.into(),
3188                            "bar".into() => "baz".into(),
3189                        },
3190                    )
3191                    .await
3192                    .unwrap(),
3193                )
3194                .build()
3195                .unwrap();
3196
3197            let jsn = json!({
3198                "_type": "targets",
3199                "spec_version": "1.0",
3200                "version": 1,
3201                "expires": "2017-01-01T00:00:00Z",
3202                "targets": {
3203                    "insert-target-from-slice": {
3204                        "length": 3,
3205                        "hashes": {
3206                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3207                                bfa0f98a5e886266e7ae",
3208                        },
3209                    },
3210                    "insert-target-description-from-slice-with-custom": {
3211                        "length": 3,
3212                        "hashes": {
3213                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3214                                bfa0f98a5e886266e7ae",
3215                        },
3216                    },
3217                    "insert-target-from-reader": {
3218                        "length": 3,
3219                        "hashes": {
3220                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3221                                bfa0f98a5e886266e7ae",
3222                        },
3223                    },
3224                    "insert-target-description-from-reader-with-custom": {
3225                        "length": 3,
3226                        "hashes": {
3227                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3228                                bfa0f98a5e886266e7ae",
3229                        },
3230                        "custom": {
3231                            "foo": 1,
3232                            "bar": "baz",
3233                        },
3234                    },
3235                },
3236            });
3237
3238            let encoded = serde_json::to_value(&targets).unwrap();
3239            assert_eq!(encoded, jsn);
3240            let decoded: TargetsMetadata = serde_json::from_value(encoded).unwrap();
3241            assert_eq!(decoded, targets);
3242        })
3243    }
3244
3245    #[test]
3246    fn serde_targets_metadata_additional_fields() {
3247        let jsn = json!({
3248                "_type": "targets",
3249                "spec_version": "1.0",
3250                "version": 1,
3251                "expires": "2017-01-01T00:00:00Z",
3252                "targets": {
3253                    "insert-target-from-slice": {
3254                        "length": 3,
3255                        "hashes": {
3256                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3257                                bfa0f98a5e886266e7ae",
3258                        },
3259                    },
3260                    "insert-target-description-from-slice-with-custom": {
3261                        "length": 3,
3262                        "hashes": {
3263                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3264                                bfa0f98a5e886266e7ae",
3265                        },
3266                    },
3267                    "insert-target-from-reader": {
3268                        "length": 3,
3269                        "hashes": {
3270                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3271                                bfa0f98a5e886266e7ae",
3272                        },
3273                    },
3274                    "insert-target-description-from-reader-with-custom": {
3275                        "length": 3,
3276                        "hashes": {
3277                            "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483\
3278                                bfa0f98a5e886266e7ae",
3279                        },
3280                        "custom": {
3281                            "foo": 1,
3282                            "bar": "baz",
3283                        },
3284                    },
3285                },
3286            // additional_fields
3287            "custom": {
3288                "foo": 42,
3289                "bar": "baz",
3290            },
3291            "quux": true,
3292        });
3293
3294        let targets: TargetsMetadata = serde_json::from_value(jsn.clone()).unwrap();
3295        assert_eq!(
3296            targets.additional_fields()["custom"],
3297            json!({"foo": 42, "bar": "baz"})
3298        );
3299        assert_eq!(targets.additional_fields()["quux"], json!(true));
3300
3301        // make sure additional_fields are passed through serialization as well
3302        assert_eq!(jsn, serde_json::to_value(&targets).unwrap());
3303    }
3304
3305    #[test]
3306    fn serde_targets_with_delegations_metadata() {
3307        let key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
3308        let delegations = Delegations::new(
3309            hashmap! { key.public().key_id().clone() => key.public().clone() },
3310            vec![Delegation::new(
3311                MetadataPath::new("foo/bar").unwrap(),
3312                false,
3313                1,
3314                hashset!(key.public().key_id().clone()),
3315                hashset!(TargetPath::new("baz/quux").unwrap()),
3316            )
3317            .unwrap()],
3318        )
3319        .unwrap();
3320
3321        let targets = TargetsMetadataBuilder::new()
3322            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
3323            .delegations(delegations)
3324            .build()
3325            .unwrap();
3326
3327        let jsn = json!({
3328            "_type": "targets",
3329            "spec_version": "1.0",
3330            "version": 1,
3331            "expires": "2017-01-01T00:00:00Z",
3332            "targets": {},
3333            "delegations": {
3334                "keys": {
3335                    "a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a": {
3336                        "keytype": "ed25519",
3337                        "scheme": "ed25519",
3338                        "keyid_hash_algorithms": ["sha256", "sha512"],
3339                        "keyval": {
3340                            "public": "eb8ac26b5c9ef0279e3be3e82262a93bce16fe58\
3341                                ee422500d38caf461c65a3b6",
3342                        }
3343                    },
3344                },
3345                "roles": [
3346                    {
3347                        "name": "foo/bar",
3348                        "terminating": false,
3349                        "threshold": 1,
3350                        "keyids": ["a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a"],
3351                        "paths": ["baz/quux"],
3352                    },
3353                ],
3354            }
3355        });
3356
3357        let encoded = serde_json::to_value(&targets).unwrap();
3358        assert_eq!(encoded, jsn);
3359        let decoded: TargetsMetadata = serde_json::from_value(encoded).unwrap();
3360        assert_eq!(decoded, targets);
3361    }
3362
3363    #[test]
3364    fn serde_signed_metadata() {
3365        let snapshot = SnapshotMetadataBuilder::new()
3366            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
3367            .insert_metadata_description(
3368                MetadataPath::new("targets").unwrap(),
3369                MetadataDescription::new(
3370                    1,
3371                    Some(100),
3372                    hashmap! { HashAlgorithm::Sha256 => HashValue::new(vec![]) },
3373                )
3374                .unwrap(),
3375            )
3376            .build()
3377            .unwrap();
3378
3379        let key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
3380
3381        let signed = SignedMetadata::<Pouf1, _>::new(&snapshot, &key).unwrap();
3382
3383        let jsn = json!({
3384            "signatures": [
3385                {
3386                    "keyid": "a9f3ebc9b138762563a9c27b6edd439959e559709babd123e8d449ba2c18c61a",
3387                    "sig": "ea48ddc7b3ea614b394e508eb8722100f94ff1a4e3aac3af09d\
3388                        a0dada4f878431e8ac26160833405ec239924dfe62edf605fee8294\
3389                        c49b4acade55c76e817602",
3390                }
3391            ],
3392            "signed": {
3393                "_type": "snapshot",
3394                "spec_version": "1.0",
3395                "version": 1,
3396                "expires": "2017-01-01T00:00:00Z",
3397                "meta": {
3398                    "targets.json": {
3399                        "version": 1,
3400                        "length": 100,
3401                        "hashes": {
3402                            "sha256": "",
3403                        },
3404                    },
3405                },
3406            },
3407        });
3408
3409        let encoded = serde_json::to_value(&signed).unwrap();
3410        assert_eq!(encoded, jsn, "{:#?} != {:#?}", encoded, jsn);
3411        let decoded: SignedMetadata<Pouf1, SnapshotMetadata> =
3412            serde_json::from_value(encoded).unwrap();
3413        assert_eq!(decoded, signed);
3414    }
3415
3416    ///////////////////////////////////////////////////////////////////////////////////////////////
3417    //
3418    // Here there be test cases about what metadata is allowed to be parsed wherein we do all sorts
3419    // of naughty things and make sure the parsers puke appropriately.
3420    //                                   ______________
3421    //                             ,===:'.,            `-._
3422    //                                  `:.`---.__         `-._
3423    //                                    `:.     `--.         `.
3424    //                                      \.        `.         `.
3425    //                              (,,(,    \.         `.   ____,-`.,
3426    //                           (,'     `/   \.   ,--.___`.'
3427    //                       ,  ,'  ,--.  `,   \.;'         `
3428    //                        `(o, /    \  :    \;
3429    //                          |,,'    /  /    //
3430    //                          j;;    /  ,' ,-//.    ,---.      ,
3431    //                          \;'   /  ,' /  _  \  /  _  \   ,'/
3432    //                                \   `'  / \  `'  / \  `.' /
3433    //                                 `.___,'   `.__,'   `.__,'
3434    //
3435    ///////////////////////////////////////////////////////////////////////////////////////////////
3436
3437    // TODO test for mismatched ed25519/rsa keys/schemes
3438
3439    fn make_root() -> serde_json::Value {
3440        let root_key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8).unwrap();
3441        let snapshot_key = Ed25519PrivateKey::from_pkcs8(ED25519_2_PK8).unwrap();
3442        let targets_key = Ed25519PrivateKey::from_pkcs8(ED25519_3_PK8).unwrap();
3443        let timestamp_key = Ed25519PrivateKey::from_pkcs8(ED25519_4_PK8).unwrap();
3444
3445        let root = RootMetadataBuilder::new()
3446            .expires(Utc.with_ymd_and_hms(2038, 1, 1, 0, 0, 0).unwrap())
3447            .root_key(root_key.public().clone())
3448            .snapshot_key(snapshot_key.public().clone())
3449            .targets_key(targets_key.public().clone())
3450            .timestamp_key(timestamp_key.public().clone())
3451            .build()
3452            .unwrap();
3453
3454        serde_json::to_value(&root).unwrap()
3455    }
3456
3457    fn make_snapshot() -> serde_json::Value {
3458        let snapshot = SnapshotMetadataBuilder::new()
3459            .expires(Utc.with_ymd_and_hms(2038, 1, 1, 0, 0, 0).unwrap())
3460            .build()
3461            .unwrap();
3462
3463        #[allow(clippy::needless_borrows_for_generic_args)]
3464        serde_json::to_value(&snapshot).unwrap()
3465    }
3466
3467    fn make_timestamp() -> serde_json::Value {
3468        let description =
3469            MetadataDescription::from_slice(&[][..], 1, &[HashAlgorithm::Sha256]).unwrap();
3470
3471        let timestamp = TimestampMetadataBuilder::from_metadata_description(description)
3472            .expires(Utc.with_ymd_and_hms(2017, 1, 1, 0, 0, 0).unwrap())
3473            .build()
3474            .unwrap();
3475
3476        #[allow(clippy::needless_borrows_for_generic_args)]
3477        serde_json::to_value(&timestamp).unwrap()
3478    }
3479
3480    fn make_targets() -> serde_json::Value {
3481        let targets = TargetsMetadata::new(
3482            1,
3483            Utc.with_ymd_and_hms(2038, 1, 1, 0, 0, 0).unwrap(),
3484            hashmap!(),
3485            Delegations::default(),
3486            Default::default(),
3487        )
3488        .unwrap();
3489
3490        serde_json::to_value(&targets).unwrap()
3491    }
3492
3493    fn make_delegations() -> serde_json::Value {
3494        let key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8)
3495            .unwrap()
3496            .public()
3497            .clone();
3498        let delegations = Delegations::new(
3499            hashmap! { key.key_id().clone() => key.clone() },
3500            vec![Delegation::new(
3501                MetadataPath::new("foo").unwrap(),
3502                false,
3503                1,
3504                hashset!(key.key_id().clone()),
3505                hashset!(TargetPath::new("bar").unwrap()),
3506            )
3507            .unwrap()],
3508        )
3509        .unwrap();
3510
3511        serde_json::to_value(&delegations).unwrap()
3512    }
3513
3514    fn make_delegation() -> serde_json::Value {
3515        let key = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8)
3516            .unwrap()
3517            .public()
3518            .clone();
3519        let delegation = Delegation::new(
3520            MetadataPath::new("foo").unwrap(),
3521            false,
3522            1,
3523            hashset!(key.key_id().clone()),
3524            hashset!(TargetPath::new("bar").unwrap()),
3525        )
3526        .unwrap();
3527
3528        serde_json::to_value(&delegation).unwrap()
3529    }
3530
3531    fn set_version(value: &mut serde_json::Value, version: i64) {
3532        match value.as_object_mut() {
3533            Some(obj) => {
3534                let _ = obj.insert("version".into(), json!(version));
3535            }
3536            None => panic!(),
3537        }
3538    }
3539
3540    // Refuse to deserialize root metadata if the version is not > 0
3541    #[test]
3542    fn deserialize_json_root_illegal_version() {
3543        let mut root_json = make_root();
3544        set_version(&mut root_json, 0);
3545        assert!(serde_json::from_value::<RootMetadata>(root_json.clone()).is_err());
3546
3547        let mut root_json = make_root();
3548        set_version(&mut root_json, -1);
3549        assert!(serde_json::from_value::<RootMetadata>(root_json).is_err());
3550    }
3551
3552    // Refuse to deserialize root metadata if it contains duplicate keys
3553    #[test]
3554    fn deserialize_json_root_duplicate_keys() {
3555        let root_json = r#"{
3556            "_type": "root",
3557            "spec_version": "1.0",
3558            "version": 1,
3559            "expires": "2017-01-01T00:00:00Z",
3560            "consistent_snapshot": false,
3561            "keys": {
3562                "09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1": {
3563                    "keytype": "ed25519",
3564                    "scheme": "ed25519",
3565                    "keyval": {
3566                        "public": "1410ae3053aa70bbfa98428a879d64d3002a3578f7dfaaeb1cb0764e860f7e0b"
3567                    }
3568                },
3569                "09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1": {
3570                    "keytype": "ed25519",
3571                    "scheme": "ed25519",
3572                    "keyval": {
3573                        "public": "166376c90a7f717d027056272f361c252fb050bed1a067ff2089a0302fbab73d"
3574                    }
3575                }
3576            },
3577            "roles": {
3578                "root": {
3579                    "threshold": 1,
3580                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"]
3581                },
3582                "snapshot": {
3583                    "threshold": 1,
3584                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"]
3585                },
3586                "targets": {
3587                    "threshold": 1,
3588                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"]
3589                },
3590                "timestamp": {
3591                    "threshold": 1,
3592                    "keyids": ["09557ed63f91b5b95917d46f66c63ea79bdaef1b008ba823808bca849f1d18a1"]
3593                }
3594            }
3595        }"#;
3596        match serde_json::from_str::<RootMetadata>(root_json) {
3597            Err(ref err) if err.is_data() => {
3598                assert!(
3599                    err.to_string().starts_with("Cannot have duplicate keys"),
3600                    "unexpected err: {:?}",
3601                    err
3602                );
3603            }
3604            result => panic!("unexpected result: {:?}", result),
3605        }
3606    }
3607
3608    fn set_threshold(value: &mut serde_json::Value, threshold: i32) {
3609        match value.as_object_mut() {
3610            Some(obj) => {
3611                let _ = obj.insert("threshold".into(), json!(threshold));
3612            }
3613            None => panic!(),
3614        }
3615    }
3616
3617    // Refuse to deserialize role definitions with illegal thresholds
3618    #[test]
3619    fn deserialize_json_role_definition_illegal_threshold() {
3620        let role_def = RoleDefinition::<RootMetadata>::new(
3621            1,
3622            hashset![Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8)
3623                .unwrap()
3624                .public()
3625                .key_id()
3626                .clone()],
3627        )
3628        .unwrap();
3629
3630        let mut jsn = serde_json::to_value(&role_def).unwrap();
3631        set_threshold(&mut jsn, 0);
3632        assert!(serde_json::from_value::<RoleDefinition<RootMetadata>>(jsn).is_err());
3633
3634        let mut jsn = serde_json::to_value(&role_def).unwrap();
3635        set_threshold(&mut jsn, -1);
3636        assert!(serde_json::from_value::<RoleDefinition<RootMetadata>>(jsn).is_err());
3637
3638        let role_def = RoleDefinition::<RootMetadata>::new(
3639            2,
3640            hashset![
3641                Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8)
3642                    .unwrap()
3643                    .public()
3644                    .key_id()
3645                    .clone(),
3646                Ed25519PrivateKey::from_pkcs8(ED25519_2_PK8)
3647                    .unwrap()
3648                    .public()
3649                    .key_id()
3650                    .clone(),
3651            ],
3652        )
3653        .unwrap();
3654
3655        let mut jsn = serde_json::to_value(&role_def).unwrap();
3656        set_threshold(&mut jsn, 3);
3657        assert!(serde_json::from_value::<RoleDefinition<RootMetadata>>(jsn).is_err());
3658    }
3659
3660    // Refuse to deserialize root metadata with wrong type field
3661    #[test]
3662    fn deserialize_json_root_bad_type() {
3663        let mut root = make_root();
3664        let _ = root
3665            .as_object_mut()
3666            .unwrap()
3667            .insert("_type".into(), json!("snapshot"));
3668        assert!(serde_json::from_value::<RootMetadata>(root).is_err());
3669    }
3670
3671    // Refuse to deserialize root metadata with unknown spec version
3672    #[test]
3673    fn deserialize_json_root_bad_spec_version() {
3674        let mut root = make_root();
3675        let _ = root
3676            .as_object_mut()
3677            .unwrap()
3678            .insert("spec_version".into(), json!("0"));
3679        assert!(serde_json::from_value::<RootMetadata>(root).is_err());
3680    }
3681
3682    // Refuse to deserialize role definitions with duplicated key ids
3683    #[test]
3684    fn deserialize_json_role_definition_duplicate_key_ids() {
3685        let key_id = Ed25519PrivateKey::from_pkcs8(ED25519_1_PK8)
3686            .unwrap()
3687            .public()
3688            .key_id()
3689            .clone();
3690        let role_def = RoleDefinition::<RootMetadata>::new(1, hashset![key_id.clone()]).unwrap();
3691        let mut jsn = serde_json::to_value(&role_def).unwrap();
3692
3693        match jsn.as_object_mut() {
3694            Some(obj) => match obj.get_mut("keyids").unwrap().as_array_mut() {
3695                Some(arr) => arr.push(json!(key_id)),
3696                None => panic!(),
3697            },
3698            None => panic!(),
3699        }
3700
3701        assert!(serde_json::from_value::<RoleDefinition<RootMetadata>>(jsn).is_err());
3702    }
3703
3704    // Refuse to deserialize snapshot metadata with illegal versions
3705    #[test]
3706    fn deserialize_json_snapshot_illegal_version() {
3707        let mut snapshot = make_snapshot();
3708        set_version(&mut snapshot, 0);
3709        assert!(serde_json::from_value::<SnapshotMetadata>(snapshot).is_err());
3710
3711        let mut snapshot = make_snapshot();
3712        set_version(&mut snapshot, -1);
3713        assert!(serde_json::from_value::<SnapshotMetadata>(snapshot).is_err());
3714    }
3715
3716    // Refuse to deserialize snapshot metadata with wrong type field
3717    #[test]
3718    fn deserialize_json_snapshot_bad_type() {
3719        let mut snapshot = make_snapshot();
3720        let _ = snapshot
3721            .as_object_mut()
3722            .unwrap()
3723            .insert("_type".into(), json!("root"));
3724        assert!(serde_json::from_value::<SnapshotMetadata>(snapshot).is_err());
3725    }
3726
3727    // Refuse to deserialize snapshot metadata with unknown spec version
3728    #[test]
3729    fn deserialize_json_snapshot_spec_version() {
3730        let mut snapshot = make_snapshot();
3731        let _ = snapshot
3732            .as_object_mut()
3733            .unwrap()
3734            .insert("spec_version".into(), json!("0"));
3735        assert!(serde_json::from_value::<SnapshotMetadata>(snapshot).is_err());
3736    }
3737
3738    // Refuse to deserialize snapshot metadata if it contains duplicate metadata
3739    #[test]
3740    fn deserialize_json_snapshot_duplicate_metadata() {
3741        let snapshot_json = r#"{
3742            "_type": "snapshot",
3743            "spec_version": "1.0",
3744            "version": 1,
3745            "expires": "2017-01-01T00:00:00Z",
3746            "meta": {
3747                "targets.json": {
3748                    "version": 1,
3749                    "length": 100,
3750                    "hashes": {
3751                        "sha256": ""
3752                    }
3753                },
3754                "targets.json": {
3755                    "version": 1,
3756                    "length": 100,
3757                    "hashes": {
3758                        "sha256": ""
3759                    }
3760                }
3761            }
3762        }"#;
3763        match serde_json::from_str::<SnapshotMetadata>(snapshot_json) {
3764            Err(ref err) if err.is_data() => {}
3765            result => panic!("unexpected result: {:?}", result),
3766        }
3767    }
3768
3769    // Refuse to deserialize timestamp metadata with illegal versions
3770    #[test]
3771    fn deserialize_json_timestamp_illegal_version() {
3772        let mut timestamp = make_timestamp();
3773        set_version(&mut timestamp, 0);
3774        assert!(serde_json::from_value::<TimestampMetadata>(timestamp).is_err());
3775
3776        let mut timestamp = make_timestamp();
3777        set_version(&mut timestamp, -1);
3778        assert!(serde_json::from_value::<TimestampMetadata>(timestamp).is_err());
3779    }
3780
3781    // Refuse to deserialize timestamp metadata with wrong type field
3782    #[test]
3783    fn deserialize_json_timestamp_bad_type() {
3784        let mut timestamp = make_timestamp();
3785        let _ = timestamp
3786            .as_object_mut()
3787            .unwrap()
3788            .insert("_type".into(), json!("root"));
3789        assert!(serde_json::from_value::<TimestampMetadata>(timestamp).is_err());
3790    }
3791
3792    // Refuse to deserialize timestamp metadata with unknown spec version
3793    #[test]
3794    fn deserialize_json_timestamp_bad_spec_version() {
3795        let mut timestamp = make_timestamp();
3796        let _ = timestamp
3797            .as_object_mut()
3798            .unwrap()
3799            .insert("spec_version".into(), json!("0"));
3800        assert!(serde_json::from_value::<TimestampMetadata>(timestamp).is_err());
3801    }
3802
3803    // Refuse to deserialize timestamp metadata if it contains duplicate metadata
3804    #[test]
3805    fn deserialize_json_timestamp_duplicate_metadata() {
3806        let timestamp_json = r#"{
3807            "_type": "timestamp",
3808            "spec_version": "1.0",
3809            "version": 1,
3810            "expires": "2017-01-01T00:00:00Z",
3811            "meta": {
3812                "snapshot.json": {
3813                    "version": 1,
3814                    "length": 100,
3815                    "hashes": {
3816                        "sha256": ""
3817                    }
3818                },
3819                "snapshot.json": {
3820                    "version": 1,
3821                    "length": 100,
3822                    "hashes": {
3823                        "sha256": ""
3824                    }
3825                }
3826            }
3827        }"#;
3828        match serde_json::from_str::<TimestampMetadata>(timestamp_json) {
3829            Err(ref err) if err.is_data() => {}
3830            result => panic!("unexpected result: {:?}", result),
3831        }
3832    }
3833
3834    // Refuse to deserialize targets metadata with illegal versions
3835    #[test]
3836    fn deserialize_json_targets_illegal_version() {
3837        let mut targets = make_targets();
3838        set_version(&mut targets, 0);
3839        assert!(serde_json::from_value::<TargetsMetadata>(targets).is_err());
3840
3841        let mut targets = make_targets();
3842        set_version(&mut targets, -1);
3843        assert!(serde_json::from_value::<TargetsMetadata>(targets).is_err());
3844    }
3845
3846    // Refuse to deserialize targets metadata with wrong type field
3847    #[test]
3848    fn deserialize_json_targets_bad_type() {
3849        let mut targets = make_targets();
3850        let _ = targets
3851            .as_object_mut()
3852            .unwrap()
3853            .insert("_type".into(), json!("root"));
3854        assert!(serde_json::from_value::<TargetsMetadata>(targets).is_err());
3855    }
3856
3857    // Refuse to deserialize targets metadata with unknown spec version
3858    #[test]
3859    fn deserialize_json_targets_bad_spec_version() {
3860        let mut targets = make_targets();
3861        let _ = targets
3862            .as_object_mut()
3863            .unwrap()
3864            .insert("spec_version".into(), json!("0"));
3865        assert!(serde_json::from_value::<TargetsMetadata>(targets).is_err());
3866    }
3867
3868    // Refuse to deserialize delegations with duplicated roles
3869    #[test]
3870    fn deserialize_json_delegations_duplicated_roles() {
3871        let mut delegations = make_delegations();
3872        let dupe = delegations
3873            .as_object()
3874            .unwrap()
3875            .get("roles")
3876            .unwrap()
3877            .as_array()
3878            .unwrap()[0]
3879            .clone();
3880        delegations
3881            .as_object_mut()
3882            .unwrap()
3883            .get_mut("roles")
3884            .unwrap()
3885            .as_array_mut()
3886            .unwrap()
3887            .push(dupe);
3888        assert!(serde_json::from_value::<Delegations>(delegations).is_err());
3889    }
3890
3891    // Refuse to deserialize a delegation with insufficient threshold
3892    #[test]
3893    fn deserialize_json_delegation_bad_threshold() {
3894        let mut delegation = make_delegation();
3895        set_threshold(&mut delegation, 0);
3896        assert!(serde_json::from_value::<Delegation>(delegation).is_err());
3897
3898        let mut delegation = make_delegation();
3899        set_threshold(&mut delegation, 2);
3900        assert!(serde_json::from_value::<Delegation>(delegation).is_err());
3901    }
3902
3903    // Refuse to deserialize a delegation with duplicate key IDs
3904    #[test]
3905    fn deserialize_json_delegation_duplicate_key_ids() {
3906        let mut delegation = make_delegation();
3907        let dupe = delegation
3908            .as_object()
3909            .unwrap()
3910            .get("keyids")
3911            .unwrap()
3912            .as_array()
3913            .unwrap()[0]
3914            .clone();
3915        delegation
3916            .as_object_mut()
3917            .unwrap()
3918            .get_mut("keyids")
3919            .unwrap()
3920            .as_array_mut()
3921            .unwrap()
3922            .push(dupe);
3923        assert!(serde_json::from_value::<Delegation>(delegation).is_err());
3924    }
3925
3926    // Refuse to deserialize a delegation with duplicate paths
3927    #[test]
3928    fn deserialize_json_delegation_duplicate_paths() {
3929        let mut delegation = make_delegation();
3930        let dupe = delegation
3931            .as_object()
3932            .unwrap()
3933            .get("paths")
3934            .unwrap()
3935            .as_array()
3936            .unwrap()[0]
3937            .clone();
3938        delegation
3939            .as_object_mut()
3940            .unwrap()
3941            .get_mut("paths")
3942            .unwrap()
3943            .as_array_mut()
3944            .unwrap()
3945            .push(dupe);
3946        assert!(serde_json::from_value::<Delegation>(delegation).is_err());
3947    }
3948
3949    // Refuse to deserialize a Delegations struct with duplicate keys
3950    #[test]
3951    fn deserialize_json_delegations_duplicate_keys() {
3952        let delegations_json = r#"{
3953            "keys": {
3954                "qfrfBrkB4lBBSDEBlZgaTGS_SrE6UfmON9kP4i3dJFY=": {
3955                    "public_key": "MCwwBwYDK2VwBQADIQDrisJrXJ7wJ5474-giYqk7zhb-WO5CJQDTjK9GHGWjtg==",
3956                    "scheme": "ed25519",
3957                    "type": "ed25519"
3958                },
3959                "qfrfBrkB4lBBSDEBlZgaTGS_SrE6UfmON9kP4i3dJFY=": {
3960                    "public_key": "MCwwBwYDK2VwBQADIQDrisJrXJ7wJ5474-giYqk7zhb-WO5CJQDTjK9GHGWjtg==",
3961                    "scheme": "ed25519",
3962                    "type": "ed25519"
3963                }
3964            },
3965            "roles": [
3966            {
3967                "keyids": [
3968                    "qfrfBrkB4lBBSDEBlZgaTGS_SrE6UfmON9kP4i3dJFY="
3969                ],
3970                "paths": [
3971                    "bar"
3972                ],
3973                "role": "foo",
3974                "terminating": false,
3975                "threshold": 1
3976            }
3977            ]
3978        }"#;
3979        match serde_json::from_str::<Delegations>(delegations_json) {
3980            Err(ref err) if err.is_data() => {}
3981            result => panic!("unexpected result: {:?}", result),
3982        }
3983    }
3984}