1use 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 ".", "..", ];
28
29#[rustfmt::skip]
30static PATH_ILLEGAL_COMPONENTS_CASE_INSENSITIVE: &[&str] = &[
31 "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 ":", "\\", "<",
66 ">",
67 "\"",
68 "|",
69 "?",
70 "\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#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
150pub enum Role {
151 #[serde(rename = "root")]
153 Root,
154
155 #[serde(rename = "snapshot")]
157 Snapshot,
158
159 #[serde(rename = "targets")]
161 Targets,
162
163 #[serde(rename = "timestamp")]
165 Timestamp,
166}
167
168impl Role {
169 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 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#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
212pub enum MetadataVersion {
213 None,
215 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 pub fn prefix(&self) -> String {
231 match *self {
232 MetadataVersion::None => String::new(),
233 MetadataVersion::Number(ref x) => format!("{}.", x),
234 }
235 }
236}
237
238pub trait Metadata: Debug + PartialEq + Serialize + DeserializeOwned {
240 const ROLE: Role;
242
243 fn version(&self) -> u32;
245
246 fn expires(&self) -> &DateTime<Utc>;
248}
249
250#[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 pub fn new(bytes: Vec<u8>) -> Self {
265 Self {
266 bytes,
267 _marker: PhantomData,
268 }
269 }
270
271 pub fn as_bytes(&self) -> &[u8] {
273 &self.bytes
274 }
275
276 pub fn parse_untrusted(&self) -> Result<SignedMetadata<D, M>> {
281 D::from_slice(&self.bytes)
282 }
283}
284
285#[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 pub fn root(&self) -> Option<&RawSignedMetadata<D, RootMetadata>> {
298 self.root.as_ref()
299 }
300
301 pub fn targets(&self) -> Option<&RawSignedMetadata<D, TargetsMetadata>> {
303 self.targets.as_ref()
304 }
305
306 pub fn snapshot(&self) -> Option<&RawSignedMetadata<D, SnapshotMetadata>> {
308 self.snapshot.as_ref()
309 }
310
311 pub fn timestamp(&self) -> Option<&RawSignedMetadata<D, TimestampMetadata>> {
313 self.timestamp.as_ref()
314 }
315}
316
317#[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 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 pub fn root(mut self, root: RawSignedMetadata<D, RootMetadata>) -> Self {
344 self.metadata.root = Some(root);
345 self
346 }
347
348 pub fn targets(mut self, targets: RawSignedMetadata<D, TargetsMetadata>) -> Self {
350 self.metadata.targets = Some(targets);
351 self
352 }
353
354 pub fn snapshot(mut self, snapshot: RawSignedMetadata<D, SnapshotMetadata>) -> Self {
356 self.metadata.snapshot = Some(snapshot);
357 self
358 }
359
360 pub fn timestamp(mut self, timestamp: RawSignedMetadata<D, TimestampMetadata>) -> Self {
362 self.metadata.timestamp = Some(timestamp);
363 self
364 }
365
366 pub fn build(self) -> RawSignedMetadataSet<D> {
368 self.metadata
369 }
370}
371
372#[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 pub fn from_metadata(metadata: &M) -> Result<Self> {
391 let metadata = D::serialize(metadata)?;
392 Self::from_raw_metadata(metadata)
393 }
394
395 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 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 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#[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 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 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 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 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 pub fn signatures(&self) -> &[Signature] {
567 &self.signatures
568 }
569
570 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 pub fn assume_valid(&self) -> Result<M> {
589 D::deserialize(&self.metadata)
590 }
591}
592
593pub 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 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 pub fn version(mut self, version: u32) -> Self {
635 self.version = version;
636 self
637 }
638
639 pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
641 self.expires = expires;
642 self
643 }
644
645 pub fn consistent_snapshot(mut self, consistent_snapshot: bool) -> Self {
647 self.consistent_snapshot = consistent_snapshot;
648 self
649 }
650
651 pub fn root_threshold(mut self, threshold: u32) -> Self {
653 self.root_threshold = threshold;
654 self
655 }
656
657 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 pub fn snapshot_threshold(mut self, threshold: u32) -> Self {
667 self.snapshot_threshold = threshold;
668 self
669 }
670
671 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 pub fn targets_threshold(mut self, threshold: u32) -> Self {
681 self.targets_threshold = threshold;
682 self
683 }
684
685 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 pub fn timestamp_threshold(mut self, threshold: u32) -> Self {
695 self.timestamp_threshold = threshold;
696 self
697 }
698
699 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 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 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#[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 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 pub fn consistent_snapshot(&self) -> bool {
805 self.consistent_snapshot
806 }
807
808 pub fn keys(&self) -> &HashMap<KeyId, PublicKey> {
810 &self.keys
811 }
812
813 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 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 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 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 pub fn root(&self) -> &RoleDefinition<RootMetadata> {
847 &self.root
848 }
849
850 pub fn snapshot(&self) -> &RoleDefinition<SnapshotMetadata> {
852 &self.snapshot
853 }
854
855 pub fn targets(&self) -> &RoleDefinition<TargetsMetadata> {
857 &self.targets
858 }
859
860 pub fn timestamp(&self) -> &RoleDefinition<TimestampMetadata> {
862 &self.timestamp
863 }
864
865 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#[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 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 pub fn threshold(&self) -> u32 {
937 self.threshold
938 }
939
940 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#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
979pub struct MetadataPath(Cow<'static, str>);
980
981impl MetadataPath {
982 pub fn root() -> Self {
984 MetadataPath(Role::Root.name().into())
985 }
986
987 pub fn timestamp() -> Self {
989 MetadataPath(Role::Timestamp.name().into())
990 }
991
992 pub fn snapshot() -> Self {
994 MetadataPath(Role::Snapshot.name().into())
995 }
996
997 pub fn targets() -> Self {
999 MetadataPath(Role::Targets.name().into())
1000 }
1001
1002 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 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
1078pub struct TimestampMetadataBuilder {
1080 version: u32,
1081 expires: DateTime<Utc>,
1082 snapshot: MetadataDescription<SnapshotMetadata>,
1083}
1084
1085impl TimestampMetadataBuilder {
1086 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 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 pub fn version(mut self, version: u32) -> Self {
1122 self.version = version;
1123 self
1124 }
1125
1126 pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
1128 self.expires = expires;
1129 self
1130 }
1131
1132 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 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#[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 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 pub fn snapshot(&self) -> &MetadataDescription<SnapshotMetadata> {
1187 &self.snapshot
1188 }
1189
1190 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#[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 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 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 pub fn version(&self) -> u32 {
1280 self.version
1281 }
1282
1283 pub fn length(&self) -> Option<usize> {
1285 self.length
1286 }
1287
1288 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
1312pub struct SnapshotMetadataBuilder {
1314 version: u32,
1315 expires: DateTime<Utc>,
1316 meta: HashMap<MetadataPath, MetadataDescription<TargetsMetadata>>,
1317}
1318
1319impl SnapshotMetadataBuilder {
1320 pub fn new() -> Self {
1325 SnapshotMetadataBuilder {
1326 version: 1,
1327 expires: Utc::now() + Duration::days(7),
1328 meta: HashMap::new(),
1329 }
1330 }
1331
1332 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 pub fn version(mut self, version: u32) -> Self {
1348 self.version = version;
1349 self
1350 }
1351
1352 pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
1354 self.expires = expires;
1355 self
1356 }
1357
1358 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 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 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 pub fn build(self) -> Result<SnapshotMetadata> {
1405 SnapshotMetadata::new(self.version, self.expires, self.meta, Default::default())
1406 }
1407
1408 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#[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 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 pub fn meta(&self) -> &HashMap<MetadataPath, MetadataDescription<TargetsMetadata>> {
1469 &self.meta
1470 }
1471
1472 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#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Serialize)]
1512pub struct TargetPath(String);
1513
1514impl TargetPath {
1515 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 pub fn components(&self) -> Vec<String> {
1543 self.0.split('/').map(|s| s.to_string()).collect()
1544 }
1545
1546 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 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 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 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#[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 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 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 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 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 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 pub fn length(&self) -> u64 {
1835 self.length
1836 }
1837
1838 pub fn hashes(&self) -> &HashMap<HashAlgorithm, HashValue> {
1840 &self.hashes
1841 }
1842
1843 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#[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 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 pub fn targets(&self) -> &HashMap<TargetPath, TargetDescription> {
1903 &self.targets
1904 }
1905
1906 pub fn delegations(&self) -> &Delegations {
1908 &self.delegations
1909 }
1910
1911 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
1949pub struct TargetsMetadataBuilder {
1951 version: u32,
1952 expires: DateTime<Utc>,
1953 targets: HashMap<TargetPath, TargetDescription>,
1954 delegations: Option<Delegations>,
1955}
1956
1957impl TargetsMetadataBuilder {
1958 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 pub fn version(mut self, version: u32) -> Self {
1973 self.version = version;
1974 self
1975 }
1976
1977 pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
1979 self.expires = expires;
1980 self
1981 }
1982
1983 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 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 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 pub fn delegations(mut self, delegations: Delegations) -> Self {
2020 self.delegations = Some(delegations);
2021 self
2022 }
2023
2024 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 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#[derive(Debug, Clone, PartialEq, Eq, Default)]
2055pub struct Delegations {
2056 keys: HashMap<KeyId, PublicKey>,
2057 roles: Vec<Delegation>,
2058}
2059
2060impl Delegations {
2061 pub fn builder() -> DelegationsBuilder {
2063 DelegationsBuilder::new()
2064 }
2065
2066 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 pub fn is_empty(&self) -> bool {
2087 self.keys.is_empty() && self.roles.is_empty()
2088 }
2089
2090 pub fn keys(&self) -> &HashMap<KeyId, PublicKey> {
2092 &self.keys
2093 }
2094
2095 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#[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 pub fn new() -> Self {
2130 Self {
2131 keys: HashMap::new(),
2132 roles: vec![],
2133 role_index: HashMap::new(),
2134 }
2135 }
2136
2137 pub fn key(mut self, key: PublicKey) -> Self {
2139 self.keys.insert(key.key_id().clone(), key);
2140 self
2141 }
2142
2143 pub fn role(mut self, delegation: Delegation) -> Self {
2145 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 pub fn build(self) -> Result<Delegations> {
2161 Delegations::new(self.keys, self.roles)
2162 }
2163}
2164
2165#[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 pub fn builder(role: MetadataPath) -> DelegationBuilder {
2178 DelegationBuilder::new(role)
2179 }
2180
2181 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 pub fn name(&self) -> &MetadataPath {
2218 &self.name
2219 }
2220
2221 pub fn terminating(&self) -> bool {
2223 self.terminating
2224 }
2225
2226 pub fn key_ids(&self) -> &HashSet<KeyId> {
2228 &self.key_ids
2229 }
2230
2231 pub fn threshold(&self) -> u32 {
2233 self.threshold
2234 }
2235
2236 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
2260pub 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 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 pub fn threshold(mut self, threshold: u32) -> Self {
2283 self.threshold = threshold;
2284 self
2285 }
2286
2287 pub fn key(mut self, key: &PublicKey) -> Self {
2289 self.key_ids.insert(key.key_id().clone());
2290 self
2291 }
2292
2293 pub fn key_id(mut self, key_id: KeyId) -> Self {
2295 self.key_ids.insert(key_id);
2296 self
2297 }
2298
2299 pub fn delegate_path(mut self, path: TargetPath) -> Self {
2301 self.paths.insert(path);
2302 self
2303 }
2304
2305 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 (true, "foo", &[&["foo"]]),
2376 (true, "foo", &[&["foo"], &["foo"]]),
2378 (false, "foo", &[&["foo/"]]),
2380 (false, "foo", &[&["foo"], &["bar"]]),
2382 (true, "foo/bar", &[&["foo/"], &["foo/bar"]]),
2384 (false, "foo/bar", &[&["baz/"], &["foo/bar"]]),
2386 (
2388 false,
2389 "foo/bar/baz",
2390 &[&["foo/"], &["foo/quux/"], &["foo/bar/baz"]],
2391 ),
2392 (false, "foo", &[&[]]),
2394 (false, "foo", &[&[], &["foo"]]),
2396 (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 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 "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 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 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 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 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(×tamp).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 "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 assert_eq!(jsn, serde_json::to_value(×tamp).unwrap());
2973 }
2974
2975 #[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(×tamp).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 "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 assert_eq!(jsn, serde_json::to_value(&snapshot).unwrap());
3122 }
3123
3124 #[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 "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 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 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(×tamp).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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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}