| extern crate chrono; |
| #[macro_use] |
| extern crate maplit; |
| extern crate tuf; |
| |
| use chrono::prelude::*; |
| use chrono::offset::Utc; |
| use tuf::Error; |
| use tuf::client::{Client, Config}; |
| use tuf::crypto::{PrivateKey, SignatureScheme, KeyId, HashAlgorithm}; |
| use tuf::interchange::{DataInterchange, Json}; |
| use tuf::metadata::{RoleDefinition, RootMetadata, Role, MetadataVersion, MetadataPath, |
| SignedMetadata, TargetDescription, TargetPath, TargetsMetadata, |
| MetadataDescription, SnapshotMetadata, TimestampMetadata}; |
| use tuf::repository::{EphemeralRepository, Repository}; |
| |
| // Ironically, this is far from simple, but it's as simple as it can be made. |
| |
| const ED25519_1_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-1.pk8.der"); |
| const ED25519_2_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-2.pk8.der"); |
| const ED25519_3_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-3.pk8.der"); |
| const ED25519_4_PK8: &'static [u8] = include_bytes!("./ed25519/ed25519-4.pk8.der"); |
| |
| #[test] |
| fn main() { |
| let mut remote = EphemeralRepository::<Json>::new(); |
| let root_key_ids = init_server(&mut remote).unwrap(); |
| init_client(&root_key_ids, remote).unwrap(); |
| } |
| |
| fn init_client(root_key_ids: &[KeyId], remote: EphemeralRepository<Json>) -> Result<(), Error> { |
| let local = EphemeralRepository::<Json>::new(); |
| let config = Config::build().finish()?; |
| |
| let mut client = Client::with_root_pinned(root_key_ids, config, local, remote)?; |
| match client.update_local() { |
| Ok(_) => (), |
| Err(e) => println!("{:?}", e), |
| } |
| let _ = client.update_remote()?; |
| client.fetch_target(&TargetPath::new("grendel".into())?) |
| } |
| |
| fn init_server(remote: &mut EphemeralRepository<Json>) -> Result<Vec<KeyId>, Error> { |
| // in real life, you wouldn't want these keys on the same machine ever |
| let root_key = PrivateKey::from_pkcs8(ED25519_1_PK8)?; |
| let snapshot_key = PrivateKey::from_pkcs8(ED25519_2_PK8)?; |
| let targets_key = PrivateKey::from_pkcs8(ED25519_3_PK8)?; |
| let timestamp_key = PrivateKey::from_pkcs8(ED25519_4_PK8)?; |
| |
| //// build the root //// |
| |
| let keys = vec![ |
| root_key.public().clone(), |
| snapshot_key.public().clone(), |
| targets_key.public().clone(), |
| timestamp_key.public().clone(), |
| ]; |
| |
| let root_def = RoleDefinition::new(1, hashset!(root_key.key_id().clone()))?; |
| let snapshot_def = RoleDefinition::new(1, hashset!(snapshot_key.key_id().clone()))?; |
| let targets_def = RoleDefinition::new(1, hashset!(targets_key.key_id().clone()))?; |
| let timestamp_def = RoleDefinition::new(1, hashset!(timestamp_key.key_id().clone()))?; |
| |
| let root = RootMetadata::new( |
| 1, |
| Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), |
| false, |
| keys, |
| root_def, |
| snapshot_def, |
| targets_def, |
| timestamp_def, |
| )?; |
| |
| let signed = |
| SignedMetadata::<Json, RootMetadata>::new(&root, &root_key, SignatureScheme::Ed25519)?; |
| |
| remote.store_metadata( |
| &Role::Root, |
| &MetadataPath::new("root".into())?, |
| &MetadataVersion::Number(1), |
| &signed, |
| )?; |
| remote.store_metadata( |
| &Role::Root, |
| &MetadataPath::new("root".into())?, |
| &MetadataVersion::None, |
| &signed, |
| )?; |
| |
| //// build the targets //// |
| |
| let target_file: &[u8] = b"things fade, alternatives exclude"; |
| let target_path = TargetPath::new("grendel".into())?; |
| let target_description = TargetDescription::from_reader(target_file, &[HashAlgorithm::Sha256])?; |
| let _ = remote.store_target(target_file, &target_path); |
| |
| let target_map = hashmap!(target_path => target_description); |
| let targets = TargetsMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), target_map, None)?; |
| |
| let signed = SignedMetadata::<Json, TargetsMetadata>::new( |
| &targets, |
| &targets_key, |
| SignatureScheme::Ed25519, |
| )?; |
| |
| remote.store_metadata( |
| &Role::Targets, |
| &MetadataPath::new("targets".into())?, |
| &MetadataVersion::Number(1), |
| &signed, |
| )?; |
| remote.store_metadata( |
| &Role::Targets, |
| &MetadataPath::new("targets".into())?, |
| &MetadataVersion::None, |
| &signed, |
| )?; |
| |
| let targets_bytes = Json::canonicalize(&Json::serialize(&signed)?)?; |
| |
| //// build the snapshot //// |
| let meta_map = |
| hashmap! { |
| MetadataPath::new("targets".into())? => |
| MetadataDescription::from_reader(&*targets_bytes, 1, &[HashAlgorithm::Sha256])?, |
| }; |
| let snapshot = SnapshotMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), meta_map)?; |
| |
| let signed = SignedMetadata::<Json, SnapshotMetadata>::new( |
| &snapshot, |
| &snapshot_key, |
| SignatureScheme::Ed25519, |
| )?; |
| |
| remote.store_metadata( |
| &Role::Snapshot, |
| &MetadataPath::new("snapshot".into())?, |
| &MetadataVersion::Number(1), |
| &signed, |
| )?; |
| remote.store_metadata( |
| &Role::Snapshot, |
| &MetadataPath::new("snapshot".into())?, |
| &MetadataVersion::None, |
| &signed, |
| )?; |
| |
| let snapshot_bytes = Json::canonicalize(&Json::serialize(&signed)?)?; |
| |
| //// build the timestamp //// |
| let snap = MetadataDescription::from_reader(&*snapshot_bytes, 1, &[HashAlgorithm::Sha256])?; |
| let timestamp = TimestampMetadata::new(1, Utc.ymd(2038, 1, 1).and_hms(0, 0, 0), snap)?; |
| |
| let signed = SignedMetadata::<Json, TimestampMetadata>::new( |
| ×tamp, |
| ×tamp_key, |
| SignatureScheme::Ed25519, |
| )?; |
| |
| remote.store_metadata( |
| &Role::Timestamp, |
| &MetadataPath::new("timestamp".into())?, |
| &MetadataVersion::Number(1), |
| &signed, |
| )?; |
| remote.store_metadata( |
| &Role::Timestamp, |
| &MetadataPath::new("timestamp".into())?, |
| &MetadataVersion::None, |
| &signed, |
| )?; |
| |
| Ok(vec![root_key.key_id().clone()]) |
| } |