From e2183b4180b42db0bf6023cfbb6f19f128a347a4 Mon Sep 17 00:00:00 2001 From: DieMyst Date: Tue, 9 Feb 2021 13:26:44 +0300 Subject: [PATCH] huge mess with errors, but it works! --- src/certificate.rs | 64 +++++++++++++------- src/revoke.rs | 6 +- src/trust.rs | 33 ++++++----- src/trust_graph.rs | 116 +++++++++++++++++++++++++++---------- src/trust_graph_storage.rs | 41 ++++++++----- 5 files changed, 178 insertions(+), 82 deletions(-) diff --git a/src/certificate.rs b/src/certificate.rs index 02b3226..ab92c9b 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -14,11 +14,16 @@ * limitations under the License. */ +use crate::certificate::CerificateError::{ + CertificateLengthError, DecodeError, ExpirationError, KeyInCertificateError, MalformedRoot, + NoTrustedRoot, VerificationError, +}; use crate::trust::{Trust, TRUST_LEN}; use fluence_identity::key_pair::KeyPair; use fluence_identity::public_key::PublicKey; use std::str::FromStr; use std::time::Duration; +use thiserror::Error as ThisError; /// Serialization format of a certificate. /// TODO @@ -33,16 +38,27 @@ pub struct Certificate { pub chain: Vec, } -#[derive(Debug)] +#[derive(ThisError, Debug)] pub enum CerificateError { + #[error("Error while decoding a certificate: {0}")] DecodeError(String), + #[error("Certificate is expired. Issued at {issued_at:?} and expired at {expires_at:?}")] ExpirationError { expires_at: String, - issued_at: String + issued_at: String, }, + #[error("Certificate does not contain a trusted root.")] + NoTrustedRoot, + #[error("Root trust did not pass verification: {0}")] + MalformedRoot(String), + #[error("There is no `issued_by` public key in a certificate")] KeyInCertificateError, + #[error("The certificate must have at least 1 trust")] CertificateLengthError, - Unexpected(String) + #[error("Trust {0} in chain did not pass verification: {1}")] + VerificationError(usize, String), + #[error("Unexpected error: {0}")] + Unexpected(String), } impl Certificate { @@ -79,7 +95,10 @@ impl Certificate { cur_time: Duration, ) -> Result { if expires_at.lt(&issued_at) { - return Err("Expiration time should be greater than issued time.".to_string()); + return Err(ExpirationError { + expires_at: format!("{:?}", expires_at), + issued_at: format!("{:?}", issued_at), + }); } // first, verify given certificate @@ -100,7 +119,7 @@ impl Certificate { } if previous_trust_num == -1 { - return Err("Your public key should be in certificate.".to_string()); + return Err(KeyInCertificateError); }; // splitting old chain to add new trust after given public key @@ -126,15 +145,15 @@ impl Certificate { let chain = &cert.chain; if chain.is_empty() { - return Err("The certificate must have at least 1 trust".to_string()); + return Err(CertificateLengthError); } // check root trust and its existence in trusted roots list let root = &chain[0]; Trust::verify(root, &root.issued_for, cur_time) - .map_err(|e| format!("Root trust did not pass verification: {}", e))?; + .map_err(|e| MalformedRoot(format!("{}", e)))?; if !trusted_roots.contains(&root.issued_for) { - return Err("Certificate does not contain a trusted root.".to_string()); + return Err(NoTrustedRoot); } // check if every element in a chain is not expired and has the correct signature @@ -143,12 +162,8 @@ impl Certificate { let trust_giver = &chain[trust_id - 1]; - Trust::verify(trust, &trust_giver.issued_for, cur_time).map_err(|e| { - format!( - "Trust {} in chain did not pass verification: {}", - trust_id, e - ) - })?; + Trust::verify(trust, &trust_giver.issued_for, cur_time) + .map_err(|e| VerificationError(trust_id, format!("{}", e)))?; } Ok(()) @@ -174,13 +189,13 @@ impl Certificate { pub fn decode(arr: &[u8]) -> Result { let trusts_offset = arr.len() - 2 - 4; if trusts_offset % TRUST_LEN != 0 { - return Err("Incorrect length of an array. Should be 2 bytes of a format, 4 bytes of a version and 104 bytes for each trust. ".to_string()); + return Err(DecodeError("Incorrect length of an array. Should be 2 bytes of a format, 4 bytes of a version and 104 bytes for each trust. ".to_string())); } let number_of_trusts = trusts_offset / TRUST_LEN; if number_of_trusts < 2 { - return Err("The certificate must have at least 2 trusts.".to_string()); + return Err(CertificateLengthError); } // TODO do match different formats and versions @@ -193,7 +208,7 @@ impl Certificate { let from = i * TRUST_LEN + 6; let to = (i + 1) * TRUST_LEN + 6; let slice = &arr[from..to]; - let t = Trust::decode(slice)?; + let t = Trust::decode(slice).map_err(|e| DecodeError(format!("{}", e)))?; chain.push(t); } @@ -213,7 +228,7 @@ impl std::fmt::Display for Certificate { } impl FromStr for Certificate { - type Err = String; + type Err = CerificateError; fn from_str(s: &str) -> Result { let str_lines: Vec<&str> = s.lines().collect(); @@ -223,7 +238,10 @@ impl FromStr for Certificate { let _version = str_lines[1]; if (str_lines.len() - 2) % 4 != 0 { - return Err(format!("Incorrect format of the certificate: {}", s)); + return Err(DecodeError(format!( + "Incorrect format of the certificate: {}", + s + ))); } let num_of_trusts = (str_lines.len() - 2) / 4; @@ -235,7 +253,13 @@ impl FromStr for Certificate { str_lines[i + 1], str_lines[i + 2], str_lines[i + 3], - )?; + ) + .map_err(|e| { + DecodeError(format!( + "Cannot convert trust number {} from string: {}", + i, e + )) + })?; trusts.push(trust); } diff --git a/src/revoke.rs b/src/revoke.rs index 5cabde5..35aa8f9 100644 --- a/src/revoke.rs +++ b/src/revoke.rs @@ -14,18 +14,18 @@ * limitations under the License. */ +use crate::revoke::RevokeError::IncorrectSignature; use crate::trust::{EXPIRATION_LEN, PK_LEN}; +use ed25519_dalek::SignatureError; use fluence_identity::key_pair::KeyPair; use fluence_identity::public_key::PublicKey; use fluence_identity::signature::Signature; use serde::{Deserialize, Serialize}; use std::time::Duration; -use ed25519_dalek::SignatureError; -use crate::revoke::RevokeError::IncorrectSignature; #[derive(Debug)] pub enum RevokeError { - IncorrectSignature(SignatureError) + IncorrectSignature(SignatureError), } /// "A document" that cancels trust created before. diff --git a/src/trust.rs b/src/trust.rs index b57635a..74a5721 100644 --- a/src/trust.rs +++ b/src/trust.rs @@ -14,6 +14,7 @@ * limitations under the License. */ +use crate::trust::TrustError::{DecodeError, SignatureError}; use derivative::Derivative; use fluence_identity::key_pair::KeyPair; use fluence_identity::public_key::PublicKey; @@ -22,7 +23,6 @@ use serde::{Deserialize, Serialize}; use std::convert::TryInto; use std::time::Duration; use thiserror::Error as ThisError; -use crate::trust::TrustError::{SignatureError, DecodeError}; pub const SIG_LEN: usize = 64; pub const PK_LEN: usize = 32; @@ -69,7 +69,7 @@ pub enum TrustError { /// Errors occured on trust decoding from differrent formats #[error("{0:?}")] - DecodeError(String) + DecodeError(String), } impl Trust { @@ -107,9 +107,13 @@ impl Trust { } /// Verifies that authorization is cryptographically correct. - pub fn verify(trust: &Trust, issued_by: &PublicKey, cur_time: Duration) -> Result<(), TrustError> { + pub fn verify( + trust: &Trust, + issued_by: &PublicKey, + cur_time: Duration, + ) -> Result<(), TrustError> { if trust.expires_at < cur_time { - return TrustError::Expired(trust.expires_at, cur_time); + return Err(TrustError::Expired(trust.expires_at, cur_time)); } let msg: &[u8] = @@ -151,18 +155,20 @@ impl Trust { #[allow(dead_code)] pub fn decode(arr: &[u8]) -> Result { if arr.len() != TRUST_LEN { - return DecodeError( + return Err(DecodeError( format!("Trust length should be 104: public key(32) + signature(64) + expiration date(8), was: {}", arr.len()) - ); + )); } - let pk = PublicKey::from_bytes(&arr[0..PK_LEN]) - .map_err(|err| DecodeError(format!("Cannot decode a public key: {}", err.to_string())))?; + let pk = PublicKey::from_bytes(&arr[0..PK_LEN]).map_err(|err| { + DecodeError(format!("Cannot decode a public key: {}", err.to_string())) + })?; let signature = &arr[PK_LEN..PK_LEN + SIG_LEN]; - let signature = Signature::from_bytes(signature) - .map_err(|err| DecodeError(format!("Cannot decode a signature: {}", err.to_string())))?; + let signature = Signature::from_bytes(signature).map_err(|err| { + DecodeError(format!("Cannot decode a signature: {}", err.to_string())) + })?; let expiration_bytes = &arr[PK_LEN + SIG_LEN..PK_LEN + SIG_LEN + EXPIRATION_LEN]; let expiration_date = u64::from_le_bytes(expiration_bytes.try_into().unwrap()); @@ -182,10 +188,10 @@ impl Trust { fn bs58_str_to_vec(str: &str, field: &str) -> Result, TrustError> { bs58::decode(str).into_vec().map_err(|e| { - format!( + DecodeError(format!( "Cannot decode `{}` from base58 format in the trust '{}': {}", field, str, e - ) + )) }) } @@ -216,7 +222,8 @@ impl Trust { // 64 bytes signature let signature = Self::bs58_str_to_vec(signature, "signature")?; - let signature = Signature::from_bytes(&signature).map_err(|err| DecodeError(err.to_string()))?; + let signature = + Signature::from_bytes(&signature).map_err(|err| DecodeError(err.to_string()))?; // Duration let expires_at = Self::str_to_duration(expires_at, "expires_at")?; diff --git a/src/trust_graph.rs b/src/trust_graph.rs index ce9ffdf..a099e26 100644 --- a/src/trust_graph.rs +++ b/src/trust_graph.rs @@ -14,21 +14,23 @@ * limitations under the License. */ -use crate::certificate::{Certificate, CerificateError}; +use crate::certificate::CerificateError::{CertificateLengthError, Unexpected}; +use crate::certificate::{CerificateError, Certificate}; use crate::public_key_hashable::PublicKeyHashable; use crate::revoke::Revoke; +use crate::revoke::RevokeError; use crate::trust::Trust; -use crate::trust_graph_storage::{Storage, StorageError}; +use crate::trust_graph::TrustGraphError::{ + CertificateCheckError, InternalStorageError, NoRoot, RevokeCheckError, +}; +use crate::trust_graph_storage::Storage; use crate::trust_node::{Auth, TrustNode}; use fluence_identity::public_key::PublicKey; use std::borrow::Borrow; use std::collections::{HashSet, VecDeque}; -use std::time::Duration; -use crate::trust_graph::TrustGraphError::{InternalStorageError, CertificateCheckError, NoRoot, RevokeCheckError}; -use crate::certificate::CerificateError::{CertificateLengthError, Unexpected}; -use crate::revoke::RevokeError; use std::convert::{From, Into}; use std::result::Result; +use std::time::Duration; /// for simplicity, we store `n` where Weight = 1/n^2 pub type Weight = u32; @@ -37,7 +39,10 @@ pub type Weight = u32; /// TODO serialization/deserialization /// TODO export a certificate from graph #[allow(dead_code)] -pub struct TrustGraph where S: Storage { +pub struct TrustGraph +where + S: Storage, +{ storage: Box, } @@ -62,19 +67,30 @@ impl From for TrustGraphError { } #[allow(dead_code)] -impl TrustGraph where S: Storage { +impl TrustGraph +where + S: Storage, +{ pub fn new(storage: Box) -> Self { Self { storage: storage } } /// Insert new root weight - pub fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) -> Result<(), TrustGraphError> { - self.storage.add_root_weight(pk, weight).map_err(|e| InternalStorageError(e.into())) + pub fn add_root_weight( + &mut self, + pk: PublicKeyHashable, + weight: Weight, + ) -> Result<(), TrustGraphError> { + self.storage + .add_root_weight(pk, weight) + .map_err(|e| InternalStorageError(e.into())) } /// Get trust by public key pub fn get(&self, pk: PublicKey) -> Result, TrustGraphError> { - self.storage.get(&pk.into()).map_err(|e| InternalStorageError(e.into())) + self.storage + .get(&pk.into()) + .map_err(|e| InternalStorageError(e.into())) } // TODO: remove cur_time from api, leave it for tests only @@ -95,18 +111,26 @@ impl TrustGraph where S: Storage { Certificate::verify(cert.borrow(), roots.as_slice(), cur_time)?; let mut chain = cert.borrow().chain.iter(); - let root_trust = chain.next().ok_or("empty chain").map_err(|e| InternalStorageError(e.into()))?; + let root_trust = chain + .next() + .ok_or("empty chain") + .map_err(|e| InternalStorageError(e.into()))?; let root_pk: PublicKeyHashable = root_trust.issued_for.clone().into(); // Insert new TrustNode for this root_pk if there wasn't one - if self.storage.get(&root_pk).map_err(|e| InternalStorageError(e.into()))?.is_none() { + if self + .storage + .get(&root_pk) + .map_err(|e| InternalStorageError(e.into()))? + .is_none() + { let mut trust_node = TrustNode::new(root_trust.issued_for.clone(), cur_time); let root_auth = Auth { trust: root_trust.clone(), issued_by: root_trust.issued_for.clone(), }; trust_node.update_auth(root_auth); - self.storage.insert(root_pk, trust_node); + self.storage.insert(root_pk, trust_node).map_err(|e| InternalStorageError(e.into()))?; } // Insert remaining trusts to the graph @@ -120,7 +144,7 @@ impl TrustGraph where S: Storage { }; self.storage - .update_auth(&pk, auth, &root_trust.issued_for, cur_time); + .update_auth(&pk, auth, &root_trust.issued_for, cur_time).map_err(|e| InternalStorageError(e.into()))?; previous_trust = trust; } @@ -133,7 +157,11 @@ impl TrustGraph where S: Storage { where P: Borrow, { - if let Some(weight) = self.storage.get_root_weight(pk.borrow().as_ref()).map_err(|e| InternalStorageError(e.into()))? { + if let Some(weight) = self + .storage + .get_root_weight(pk.borrow().as_ref()) + .map_err(|e| InternalStorageError(e.into()))? + { return Ok(Some(weight)); } @@ -163,7 +191,7 @@ impl TrustGraph where S: Storage { // if there are no certificates for the given public key, there is no info about this public key // or some elements of possible certificate chains was revoked if certs.peek().is_none() { - return Ok(None) + return Ok(None); } let mut weight = std::u32::MAX; @@ -171,13 +199,17 @@ impl TrustGraph where S: Storage { for cert in certs { let c = cert.borrow(); - let first = c.chain.first().ok_or(CertificateCheckError(CertificateLengthError))?; + let first = c + .chain + .first() + .ok_or(CertificateCheckError(CertificateLengthError))?; let root_weight = self .storage .get_root_weight(first.issued_for.as_ref()) // This panic shouldn't happen // TODO: why? - .map_err(|e| InternalStorageError(e.into()))?.ok_or(NoRoot)?; + .map_err(|e| InternalStorageError(e.into()))? + .ok_or(NoRoot)?; // certificate weight = root weight + 1 * every other element in the chain // (except root, so the formula is `root weight + chain length - 1`) @@ -220,9 +252,10 @@ impl TrustGraph where S: Storage { .storage .get(&last.issued_by.clone().into()) .map_err(|e| InternalStorageError(e.into()))? - .ok_or( - CertificateCheckError(Unexpected("there cannot be paths without any nodes after adding verified certificates".to_string())), - )? + .ok_or(CertificateCheckError(Unexpected( + "there cannot be paths without any nodes after adding verified certificates" + .to_string(), + )))? .authorizations() .cloned() .collect(); @@ -258,15 +291,25 @@ impl TrustGraph where S: Storage { // TODO: remove `roots` argument from api, leave it for tests and internal usage only /// Get all possible certificates where `issued_for` will be the last element of the chain /// and one of the destinations is the root of this chain. - pub fn get_all_certs

(&self, issued_for: P, roots: &[PublicKey]) -> Result, TrustGraphError> + pub fn get_all_certs

( + &self, + issued_for: P, + roots: &[PublicKey], + ) -> Result, TrustGraphError> where P: Borrow, { // get all auths (edges) for issued public key - let issued_for_node = self.storage.get(issued_for.borrow().as_ref()).map_err(|e| InternalStorageError(e.into()))?; + let issued_for_node = self + .storage + .get(issued_for.borrow().as_ref()) + .map_err(|e| InternalStorageError(e.into()))?; let roots = roots.iter().map(|pk| pk.as_ref()); - let keys = self.storage.root_keys().map_err(|e| InternalStorageError(e.into()))?; + let keys = self + .storage + .root_keys() + .map_err(|e| InternalStorageError(e.into()))?; let roots = keys.iter().chain(roots).collect(); match issued_for_node { @@ -299,7 +342,9 @@ impl TrustGraph where S: Storage { let pk: PublicKeyHashable = revoke.pk.clone().into(); - self.storage.revoke(&pk, revoke).map_err(|e| InternalStorageError(e.into())) + self.storage + .revoke(&pk, revoke) + .map_err(|e| InternalStorageError(e.into())) } /// Check information about new certificates and about revoked certificates. @@ -421,7 +466,8 @@ mod tests { chain_keys.insert(5, key_pair1.clone()); chain_keys.insert(6, key_pair2.clone()); - let (key_pairs1, cert1) = generate_cert_with(10, chain_keys, far_future * 2, far_future).expect(""); + let (key_pairs1, cert1) = + generate_cert_with(10, chain_keys, far_future * 2, far_future).expect(""); // Use key_pair1 and key_pair2 for 7th and 8th trust in the cert chain let mut chain_keys = HashMap::new(); @@ -550,7 +596,9 @@ mod tests { graph.add(cert.clone(), current_time()).unwrap(); - let certs = graph.get_all_certs(key_pairs.last().unwrap().public_key(), &[root1_pk]).unwrap(); + let certs = graph + .get_all_certs(key_pairs.last().unwrap().public_key(), &[root1_pk]) + .unwrap(); assert_eq!(certs.len(), 1); assert_eq!(certs[0], cert); @@ -617,17 +665,23 @@ mod tests { let roots_values = [root1_pk, root2_pk, root3_pk]; - let certs1 = graph.get_all_certs(key_pair1.public_key(), &roots_values).unwrap(); + let certs1 = graph + .get_all_certs(key_pair1.public_key(), &roots_values) + .unwrap(); let lenghts1: Vec = certs1.iter().map(|c| c.chain.len()).collect(); let check_lenghts1: Vec = vec![3, 4, 4, 5, 5]; assert_eq!(lenghts1, check_lenghts1); - let certs2 = graph.get_all_certs(key_pair2.public_key(), &roots_values).unwrap(); + let certs2 = graph + .get_all_certs(key_pair2.public_key(), &roots_values) + .unwrap(); let lenghts2: Vec = certs2.iter().map(|c| c.chain.len()).collect(); let check_lenghts2: Vec = vec![4, 4, 4, 5, 5]; assert_eq!(lenghts2, check_lenghts2); - let certs3 = graph.get_all_certs(key_pair3.public_key(), &roots_values).unwrap(); + let certs3 = graph + .get_all_certs(key_pair3.public_key(), &roots_values) + .unwrap(); let lenghts3: Vec = certs3.iter().map(|c| c.chain.len()).collect(); let check_lenghts3: Vec = vec![3, 3, 5]; assert_eq!(lenghts3, check_lenghts3); diff --git a/src/trust_graph_storage.rs b/src/trust_graph_storage.rs index d171d78..d37c9db 100644 --- a/src/trust_graph_storage.rs +++ b/src/trust_graph_storage.rs @@ -1,26 +1,24 @@ use crate::public_key_hashable::PublicKeyHashable; use crate::revoke::Revoke; use crate::trust_graph::Weight; +use crate::trust_graph_storage::InMemoryStorageError::RevokeError; use crate::trust_node::{Auth, TrustNode}; use fluence_identity::public_key::PublicKey; use std::collections::HashMap; use std::time::Duration; use thiserror::Error as ThisError; -use crate::trust_graph_storage::InMemoryStorageError::RevokeError; - -pub trait StorageError {} - +pub trait StorageError: std::error::Error {} pub trait Storage { - type Error: StorageError + Into; fn get(&self, pk: &PublicKeyHashable) -> Result, Self::Error>; fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode) -> Result<(), Self::Error>; fn get_root_weight(&self, pk: &PublicKeyHashable) -> Result, Self::Error>; - fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) -> Result<(), Self::Error>; + fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) + -> Result<(), Self::Error>; fn root_keys(&self) -> Result, Self::Error>; fn revoke(&mut self, pk: &PublicKeyHashable, revoke: Revoke) -> Result<(), Self::Error>; fn update_auth( @@ -62,15 +60,19 @@ impl InMemoryStorage { #[derive(ThisError, Debug)] pub enum InMemoryStorageError { - - #[error("{0:?}")] - RevokeError(String) + #[error("InMemoryStorageError::RevokeError {0:?}")] + RevokeError(String), } -impl StorageError for InMemoryStorage {} +impl From for String { + fn from(err: InMemoryStorageError) -> Self { + err.into() + } +} + +impl StorageError for InMemoryStorageError {} impl Storage for InMemoryStorage { - type Error = InMemoryStorageError; fn get(&self, pk: &PublicKeyHashable) -> Result, Self::Error> { @@ -86,8 +88,13 @@ impl Storage for InMemoryStorage { Ok(self.root_weights.get(pk).cloned()) } - fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) -> Result<(), Self::Error> { - Ok(&self.root_weights.insert(pk, weight)); + fn add_root_weight( + &mut self, + pk: PublicKeyHashable, + weight: Weight, + ) -> Result<(), Self::Error> { + &self.root_weights.insert(pk, weight); + Ok({}) } fn root_keys(&self) -> Result, Self::Error> { @@ -100,7 +107,9 @@ impl Storage for InMemoryStorage { trust_node.update_revoke(revoke); Ok(()) } - None => RevokeError("There is no trust with such PublicKey".to_string()), + None => Err(RevokeError( + "There is no trust with such PublicKey".to_string(), + )), } } @@ -110,15 +119,17 @@ impl Storage for InMemoryStorage { auth: Auth, issued_for: &PublicKey, cur_time: Duration, - ) { + ) -> Result<(), InMemoryStorageError> { match self.nodes.get_mut(&pk) { Some(trust_node) => { trust_node.update_auth(auth); + Ok({}) } None => { let mut trust_node = TrustNode::new(issued_for.clone(), cur_time); trust_node.update_auth(auth); self.nodes.insert(pk.clone(), trust_node); + Ok({}) } } }