From b3d73ade3ddf065cdcfec819ae20acdad994cdc0 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Tue, 20 Nov 2018 15:27:02 +0100 Subject: [PATCH] Process repository response in publisher client. --- src/provisioning/identity.rs | 56 ------------ src/provisioning/info.rs | 166 +++++++++++++++++++++++++++++++++++ src/provisioning/mod.rs | 2 +- src/pubc/client.rs | 97 ++++++++++++++++++-- src/pubd/server.rs | 30 ++----- src/test/mod.rs | 26 ++++-- tests/integration_test.rs | 1 - 7 files changed, 282 insertions(+), 96 deletions(-) delete mode 100644 src/provisioning/identity.rs create mode 100644 src/provisioning/info.rs diff --git a/src/provisioning/identity.rs b/src/provisioning/identity.rs deleted file mode 100644 index ee7628f0..00000000 --- a/src/provisioning/identity.rs +++ /dev/null @@ -1,56 +0,0 @@ -use ext_serde; -use rpki::remote::idcert::IdCert; -use rpki::signing::signer::KeyId; - - -//------------ MyIdentity ---------------------------------------------------- - -/// This type stores identity details for a client or server involved in RPKI -/// provisioning (up-down) or publication. - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct MyIdentity { - name: String, - - #[serde( - deserialize_with = "ext_serde::de_id_cert", - serialize_with = "ext_serde::ser_id_cert")] - id_cert: IdCert, - - #[serde( - deserialize_with = "ext_serde::de_key_id", - serialize_with = "ext_serde::ser_key_id")] - key_id: KeyId -} - -impl MyIdentity { - pub fn new(name: String, id_cert: IdCert, key_id: KeyId) -> Self { - MyIdentity { - name, - id_cert, - key_id - } - } - - pub fn name(&self) -> &str { - self.name.as_str() - } - - pub fn id_cert(&self) -> &IdCert { - &self.id_cert - } - - pub fn key_id(&self) -> &KeyId { - &self.key_id - } -} - -impl PartialEq for MyIdentity { - fn eq(&self, other: &MyIdentity) -> bool { - self.name == other.name && - self.id_cert.to_bytes() == other.id_cert.to_bytes() && - self.key_id == other.key_id - } -} - -impl Eq for MyIdentity {} diff --git a/src/provisioning/info.rs b/src/provisioning/info.rs new file mode 100644 index 00000000..38df96d8 --- /dev/null +++ b/src/provisioning/info.rs @@ -0,0 +1,166 @@ +use ext_serde; +use rpki::remote::idcert::IdCert; +use rpki::signing::signer::KeyId; +use rpki::uri; + + +//------------ MyIdentity ---------------------------------------------------- + +/// This type stores identity details for a client or server involved in RPKI +/// provisioning (up-down) or publication. + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct MyIdentity { + name: String, + + #[serde( + deserialize_with = "ext_serde::de_id_cert", + serialize_with = "ext_serde::ser_id_cert")] + id_cert: IdCert, + + #[serde( + deserialize_with = "ext_serde::de_key_id", + serialize_with = "ext_serde::ser_key_id")] + key_id: KeyId +} + +impl MyIdentity { + pub fn new(name: String, id_cert: IdCert, key_id: KeyId) -> Self { + MyIdentity { + name, + id_cert, + key_id + } + } + + /// The name for this actor. + pub fn name(&self) -> &str { + self.name.as_str() + } + + /// The identity certificate for this actor. + pub fn id_cert(&self) -> &IdCert { + &self.id_cert + } + + /// The identifier that the Signer needs to use the key for the identity + /// certificate. + pub fn key_id(&self) -> &KeyId { + &self.key_id + } +} + +impl PartialEq for MyIdentity { + fn eq(&self, other: &MyIdentity) -> bool { + self.name == other.name && + self.id_cert.to_bytes() == other.id_cert.to_bytes() && + self.key_id == other.key_id + } +} + +impl Eq for MyIdentity {} + + +//------------ ParentInfo ---------------------------------------------------- + +/// This type stores details about a parent publication server: in +/// particular, its identity and where it may be contacted. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ParentInfo { + publisher_handle: String, + + #[serde( + deserialize_with = "ext_serde::de_id_cert", + serialize_with = "ext_serde::ser_id_cert")] + id_cert: IdCert, + + #[serde( + deserialize_with = "ext_serde::de_http_uri", + serialize_with = "ext_serde::ser_http_uri")] + service_uri: uri::Http, +} + +impl ParentInfo { + pub fn new( + publisher_handle: String, + id_cert: IdCert, + service_uri: uri::Http, + ) -> Self { + ParentInfo { + publisher_handle, + id_cert, + service_uri, + } + } + + /// The Identity Certificate used by the parent. + pub fn id_cert(&self) -> &IdCert { + &self.id_cert + } + + /// The service URI where the client should send requests. + pub fn service_uri(&self) -> &uri::Http { + &self.service_uri + } + + /// The name the publication server prefers to go by + pub fn publisher_handle(&self) -> &String { + &self.publisher_handle + } +} + +impl PartialEq for ParentInfo { + fn eq(&self, other: &ParentInfo) -> bool { + self.id_cert.to_bytes() == other.id_cert.to_bytes() && + self.service_uri == other.service_uri && + self.publisher_handle == other.publisher_handle + } +} + +impl Eq for ParentInfo {} + + +//------------ MyRepoInfo ---------------------------------------------------- + +/// This type stores details about the repository URIs available to a +/// publisher. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct MyRepoInfo { + #[serde( + deserialize_with = "ext_serde::de_rsync_uri", + serialize_with = "ext_serde::ser_rsync_uri")] + sia_base: uri::Rsync, + + #[serde( + deserialize_with = "ext_serde::de_http_uri", + serialize_with = "ext_serde::ser_http_uri")] + notify_sia: uri::Http +} + +impl MyRepoInfo { + pub fn new( + sia_base: uri::Rsync, + notify_sia: uri::Http + ) -> Self { + MyRepoInfo { sia_base, notify_sia } + } + + /// The base rsync directory under which the publisher may publish. + // XXX TODO: Read whether standards allow sub-dirs + pub fn sia_base(&self) -> &uri::Rsync { + &self.sia_base + } + + pub fn notify_sia(&self) -> &uri::Http { + &self.notify_sia + } +} + +impl PartialEq for MyRepoInfo { + fn eq(&self, other: &MyRepoInfo) -> bool { + self.sia_base == other.sia_base && + self.notify_sia == other.notify_sia + } +} + +impl Eq for MyRepoInfo {} diff --git a/src/provisioning/mod.rs b/src/provisioning/mod.rs index b11ccc44..84238498 100644 --- a/src/provisioning/mod.rs +++ b/src/provisioning/mod.rs @@ -1,3 +1,3 @@ -pub mod identity; +pub mod info; pub mod publisher; pub mod publisher_list; \ No newline at end of file diff --git a/src/pubc/client.rs b/src/pubc/client.rs index 20df6f5e..bc3bb61c 100644 --- a/src/pubc/client.rs +++ b/src/pubc/client.rs @@ -9,11 +9,14 @@ use rpki::oob::exchange::PublisherRequest; use rpki::signing::PublicKeyAlgorithm; use rpki::signing::builder::IdCertBuilder; use rpki::signing::signer::{CreateKeyError, KeyUseError, Signer}; -use provisioning::identity::MyIdentity; +use provisioning::info::MyIdentity; use signing::softsigner; use signing::softsigner::OpenSslSigner; use storage::caching_ks::CachingDiskKeyStore; use storage::keystore::{self, Info, Key, KeyStore}; +use rpki::oob::exchange::RepositoryResponse; +use provisioning::info::ParentInfo; +use provisioning::info::MyRepoInfo; /// # Some constants for naming resources in the keystore for clients. @@ -25,10 +28,25 @@ fn my_id_key() -> Key { Key::from_str("my_id") } +fn my_parent_key() -> Key { + Key::from_str("my_parent") +} + +fn my_repo_key() -> Key { + Key::from_str("my_repo") +} + fn my_id_msg() -> String { "initialised identity".to_string() } +fn my_parent_msg() -> String { + "updated parent info".to_string() +} + +fn my_repo_msg() -> String { + "update repo info".to_string() +} //------------ PubClient ----------------------------------------------------- @@ -40,11 +58,10 @@ pub struct PubClient { // key value store store: CachingDiskKeyStore, - // my_id -> MyIdentity - // -> my parent - // -> service uri - // -> parent id certificate - // -> my base uri + // my_id -> MyIdentity + // my_parent -> ParentInfo + // my_repo -> MyRepoInfo + // -> my directory of interest // (note: we do not keep this state in client, truth is on disk) // archive / log @@ -85,8 +102,37 @@ impl PubClient { } /// Process the publication server parent response. - pub fn process_parent_id(&mut self) -> Result<(), Error> { - unimplemented!() + pub fn process_repo_response( + &mut self, + response: RepositoryResponse + ) -> Result<(), Error> { + + // Store parent info + { + let parent_val = ParentInfo::new( + response.publisher_handle().clone(), + response.id_cert().clone(), + response.service_uri().clone() + ); + let parent_info = Info::now(actor(), my_parent_msg()); + let parent_key = my_parent_key(); + + self.store.store(parent_key, parent_val, parent_info)?; + } + + // Store repo info + { + let repo_val = MyRepoInfo::new( + response.sia_base().clone(), + response.rrdp_notification_uri().clone() + ); + let repo_info = Info::now(actor(), my_repo_msg()); + let repo_key = my_repo_key(); + + self.store.store(repo_key, repo_val, repo_info)?; + } + + Ok(()) } pub fn publisher_request(&self) -> Result { @@ -175,6 +221,21 @@ impl From for Error { mod tests { use super::*; use test; + use pubd::server::PubServer; + + fn test_server(work_dir: &PathBuf, xml_dir: &PathBuf) -> PubServer { + // Start up a server + let uri = test::rsync_uri("rsync://host/module/"); + let service = test::http_uri("http://host/publish"); + let notify = test::http_uri("http://host/notify.xml"); + PubServer::new( + work_dir.clone(), + xml_dir.clone(), + uri, + service, + notify + ).unwrap() + } #[test] fn should_initialise_keep_state_and_reinitialise() { @@ -199,7 +260,27 @@ mod tests { assert_ne!(pr_1.id_cert().to_bytes(), pr_2.id_cert().to_bytes()); assert_ne!(client_1, client_2); }); + } + #[test] + fn should_process_repo_response() { + test::test_with_tmp_dir(|d| { + let xml_dir = test::create_sub_dir(&d); + + let alice_dir = test::create_sub_dir(&d); + let mut alice = PubClient::new(alice_dir).unwrap(); + alice.init("alice".to_string()).unwrap(); + let pr_alice = alice.publisher_request().unwrap(); + + test::save_file(&xml_dir, "alice.xml", &pr_alice.encode_vec()); + + let mut server = test_server(&d, &xml_dir); + server.init_identity_if_empty().unwrap(); + + let response = server.repository_response("alice").unwrap(); + + alice.process_repo_response(response).unwrap(); + }); } } \ No newline at end of file diff --git a/src/pubd/server.rs b/src/pubd/server.rs index 14ef8772..9504d108 100644 --- a/src/pubd/server.rs +++ b/src/pubd/server.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use std::sync::Arc; -use provisioning::identity::MyIdentity; +use provisioning::info::MyIdentity; use provisioning::publisher_list; use provisioning::publisher_list::PublisherList; use rpki::uri; @@ -213,20 +213,8 @@ impl From for Error { #[cfg(test)] mod tests { use super::*; - use std::fs::File; - use std::io::Write; use test; use pubc::client::PubClient; - use rpki::oob::exchange::PublisherRequest; - - fn save_pr(base_dir: &PathBuf, file_name: &str, pr: &PublisherRequest) { - let mut full_name = base_dir.clone(); - full_name.push(PathBuf::from - (file_name)); - let mut f = File::create(full_name).unwrap(); - let xml = pr.encode_vec(); - f.write(xml.as_ref()).unwrap(); - } fn test_server(work_dir: &PathBuf, xml_dir: &PathBuf) -> PubServer { // Start up a server @@ -280,8 +268,8 @@ mod tests { bob.init("bob".to_string()).unwrap(); let pr_bob = bob.publisher_request().unwrap(); - save_pr(&xml_dir, "alice.xml", &pr_alice); - save_pr(&xml_dir, "bob.xml", &pr_bob); + test::save_file(&xml_dir, "alice.xml", &pr_alice.encode_vec()); + test::save_file(&xml_dir, "bob.xml", &pr_bob.encode_vec()); // Start up a server let server = test_server(&d, &xml_dir); @@ -292,7 +280,7 @@ mod tests { // Create a new xml dir with only alice.xml let xml_dir = PathBuf::from(test::create_sub_dir(&d)); - save_pr(&xml_dir, "alice.xml", &pr_alice); + test::save_file(&xml_dir, "alice.xml", &pr_alice.encode_vec()); // Start a new server (so that it re-syncs) let server = test_server(&d, &xml_dir); @@ -321,8 +309,8 @@ mod tests { carol.init("carol".to_string()).unwrap(); let pr_carol = carol.publisher_request().unwrap(); - save_pr(&xml_dir, "alice.xml", &pr_alice); - save_pr(&xml_dir, "carol.xml", &pr_carol); + test::save_file(&xml_dir, "alice.xml", &pr_alice.encode_vec()); + test::save_file(&xml_dir, "carol.xml", &pr_carol.encode_vec()); let server = test_server(&d, &xml_dir); @@ -350,7 +338,7 @@ mod tests { // However, initialising the server with two or more xml files // for the same handle results in an error. - save_pr(&xml_dir, "alice-2.xml", &pr_alice); + test::save_file(&xml_dir, "alice-2.xml", &pr_alice.encode_vec()); let uri = test::rsync_uri("rsync://host/module/"); let service = test::http_uri("http://host/publish"); @@ -383,8 +371,8 @@ mod tests { bob.init("bob".to_string()).unwrap(); let pr_bob = bob.publisher_request().unwrap(); - save_pr(&xml_dir, "alice.xml", &pr_alice); - save_pr(&xml_dir, "bob.xml", &pr_bob); + test::save_file(&xml_dir, "alice.xml", &pr_alice.encode_vec()); + test::save_file(&xml_dir, "bob.xml", &pr_bob.encode_vec()); let mut server = test_server(&d, &xml_dir); server.init_identity_if_empty().unwrap(); diff --git a/src/test/mod.rs b/src/test/mod.rs index a389ac9d..e04da8f8 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -1,12 +1,13 @@ -// Note: suppressing unused imports here, because this is only used with -#[allow(unused_imports)] use std::path::PathBuf; -#[allow(unused_imports)] use rpki::oob::exchange::PublisherRequest; -#[allow(unused_imports)] use rpki::uri; -#[allow(unused_imports)] use rpki::remote::idcert::IdCert; -#[allow(unused_imports)] use rpki::signing::builder::IdCertBuilder; -#[allow(unused_imports)] use rpki::signing::signer::Signer; -#[allow(unused_imports)] use rpki::signing::softsigner::OpenSslSigner; -#[allow(unused_imports)] use rpki::signing::PublicKeyAlgorithm; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use rpki::oob::exchange::PublisherRequest; +use rpki::uri; +use rpki::remote::idcert::IdCert; +use rpki::signing::builder::IdCertBuilder; +use rpki::signing::signer::Signer; +use rpki::signing::softsigner::OpenSslSigner; +use rpki::signing::PublicKeyAlgorithm; pub fn test_with_tmp_dir(op: F) where F: FnOnce(PathBuf) -> () { use std::fs; @@ -58,4 +59,11 @@ pub fn new_publisher_request(publisher_handle: &str) -> PublisherRequest { publisher_handle, id_cert ) +} + +pub fn save_file(base_dir: &PathBuf, file_name: &str, content: &[u8]) { + let mut full_name = base_dir.clone(); + full_name.push(PathBuf::from(file_name)); + let mut f = File::create(full_name).unwrap(); + f.write(content).unwrap(); } \ No newline at end of file diff --git a/tests/integration_test.rs b/tests/integration_test.rs index e55d1f31..079f6e85 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -113,7 +113,6 @@ fn testing() { println!("{}", e); }); - rt.block_on(fut).unwrap();