1use crate::trust::TrustError::{
18 Base58DecodeError, DecodeErrorInvalidSize, DecodePublicKeyError, ParseError, SignatureError,
19};
20use derivative::Derivative;
21use fluence_keypair::key_pair::KeyPair;
22use fluence_keypair::public_key::PublicKey;
23use fluence_keypair::signature::Signature;
24use serde::{Deserialize, Serialize};
25use sha2::Digest;
26use std::convert::TryInto;
27use std::num::ParseIntError;
28use std::time::Duration;
29use thiserror::Error as ThisError;
30
31pub const EXPIRATION_LEN: usize = 8;
32pub const ISSUED_LEN: usize = 8;
33
34#[derive(Clone, PartialEq, Derivative, Eq, Deserialize, Serialize)]
37#[derivative(Debug)]
38pub struct Trust {
39 #[derivative(Debug(format_with = "show_pubkey"))]
41 pub issued_for: PublicKey,
42 pub expires_at: Duration,
44 #[derivative(Debug(format_with = "show_sig"))]
47 pub signature: Signature,
48 pub issued_at: Duration,
50}
51
52fn show_pubkey(key: &PublicKey, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
53 write!(f, "{}", bs58::encode(&key.encode()).into_string())
54}
55
56fn show_sig(sig: &Signature, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
57 write!(f, "{}", bs58::encode(&sig.encode()).into_string())
58}
59
60#[derive(ThisError, Debug)]
61pub enum TrustError {
62 #[error("Trust is expired at: '{0:?}', current time: '{1:?}'")]
64 Expired(Duration, Duration),
65
66 #[error("{0}")]
68 SignatureError(
69 #[from]
70 #[source]
71 fluence_keypair::error::VerificationError,
72 ),
73
74 #[error("Cannot decode the public key: {0} in the trust: {1}")]
76 DecodePublicKeyError(String, #[source] fluence_keypair::error::DecodingError),
77
78 #[error("Cannot parse `{0}` field in the trust '{1}': {2}")]
79 ParseError(String, String, #[source] ParseIntError),
80
81 #[error("Cannot decode `{0}` from base58 format in the trust '{1}': {2}")]
82 Base58DecodeError(String, String, #[source] bs58::decode::Error),
83
84 #[error("{0}")]
85 PublicKeyError(
86 #[from]
87 #[source]
88 fluence_keypair::error::DecodingError,
89 ),
90
91 #[error("Cannot decode `{0}` field in the trust: invalid size")]
92 DecodeErrorInvalidSize(String),
93}
94
95impl Trust {
96 #[allow(dead_code)]
97 pub fn new(
98 issued_for: PublicKey,
99 expires_at: Duration,
100 issued_at: Duration,
101 signature: Signature,
102 ) -> Self {
103 Self {
104 issued_for,
105 expires_at,
106 issued_at,
107 signature,
108 }
109 }
110
111 pub fn create(
112 issued_by: &KeyPair,
113 issued_for: PublicKey,
114 expires_at: Duration,
115 issued_at: Duration,
116 ) -> Self {
117 let msg = Self::signature_bytes(&issued_for, expires_at, issued_at);
118
119 let signature = issued_by.sign(msg.as_slice()).unwrap();
120
121 Self {
122 issued_for,
123 expires_at,
124 signature,
125 issued_at,
126 }
127 }
128
129 pub fn verify(
131 trust: &Trust,
132 issued_by: &PublicKey,
133 cur_time: Duration,
134 ) -> Result<(), TrustError> {
135 if trust.expires_at < cur_time {
136 return Err(TrustError::Expired(trust.expires_at, cur_time));
137 }
138
139 let msg: &[u8] =
140 &Self::signature_bytes(&trust.issued_for, trust.expires_at, trust.issued_at);
141
142 KeyPair::verify(issued_by, msg, &trust.signature).map_err(SignatureError)
143 }
144
145 pub fn signature_bytes(pk: &PublicKey, expires_at: Duration, issued_at: Duration) -> Vec<u8> {
146 let pk_encoded = pk.encode();
147 let expires_at_encoded: [u8; EXPIRATION_LEN] = expires_at.as_secs().to_le_bytes();
148 let issued_at_encoded: [u8; ISSUED_LEN] = issued_at.as_secs().to_le_bytes();
149 let mut metadata = Vec::new();
150
151 metadata.extend(pk_encoded);
152 metadata.extend_from_slice(&expires_at_encoded[0..EXPIRATION_LEN]);
153 metadata.extend_from_slice(&issued_at_encoded[0..ISSUED_LEN]);
154
155 sha2::Sha256::digest(&metadata).to_vec()
156 }
157
158 #[allow(dead_code)]
160 pub fn encode(&self) -> Vec<u8> {
161 let mut vec = Vec::new();
162 let mut issued_for = self.issued_for.encode();
163 let mut signature = self.signature.encode();
164 vec.push(issued_for.len() as u8);
165 vec.append(&mut issued_for);
166 vec.push(signature.len() as u8);
167 vec.append(&mut signature);
168 vec.extend_from_slice(&self.expires_at.as_secs().to_le_bytes());
169 vec.extend_from_slice(&self.issued_at.as_secs().to_le_bytes());
170
171 vec
172 }
173
174 fn check_arr_len(arr: &[u8], field_name: &str, check_len: usize) -> Result<(), TrustError> {
175 if arr.len() < check_len {
176 Err(DecodeErrorInvalidSize(field_name.to_string()))
177 } else {
178 Ok(())
179 }
180 }
181
182 #[allow(dead_code)]
184 pub fn decode(arr: &[u8]) -> Result<Self, TrustError> {
185 Self::check_arr_len(arr, "public_key_len", 1)?;
186 let pk_len = arr[0] as usize;
187 let mut offset = 1;
188
189 Self::check_arr_len(arr, "public_key", offset + pk_len)?;
190 let pk = PublicKey::decode(&arr[offset..offset + pk_len])?;
191 offset += pk_len;
192
193 Self::check_arr_len(arr, "signature_size", offset + 1)?;
194 let signature_len = arr[offset] as usize;
195 offset += 1;
196
197 Self::check_arr_len(arr, "signature", offset + signature_len)?;
198 let signature = &arr[offset..offset + signature_len];
199 let signature = Signature::decode(signature.to_vec())?;
200 offset += signature_len;
201
202 Self::check_arr_len(arr, "expiration", offset + EXPIRATION_LEN)?;
203 let expiration_bytes = &arr[offset..offset + EXPIRATION_LEN];
204 let expiration_date = u64::from_le_bytes(expiration_bytes.try_into().unwrap());
205 let expiration_date = Duration::from_secs(expiration_date);
206 offset += EXPIRATION_LEN;
207
208 Self::check_arr_len(arr, "issued", offset + ISSUED_LEN)?;
209 let issued_bytes = &arr[offset..];
210 let issued_date = u64::from_le_bytes(issued_bytes.try_into().unwrap());
211 let issued_date = Duration::from_secs(issued_date);
212
213 Ok(Self {
214 issued_for: pk,
215 signature,
216 expires_at: expiration_date,
217 issued_at: issued_date,
218 })
219 }
220
221 fn bs58_str_to_vec(str: &str, field: &str) -> Result<Vec<u8>, TrustError> {
222 bs58::decode(str)
223 .into_vec()
224 .map_err(|e| Base58DecodeError(field.to_string(), str.to_string(), e))
225 }
226
227 fn str_to_duration(str: &str, field: &str) -> Result<Duration, TrustError> {
228 let secs = str
229 .parse()
230 .map_err(|e| ParseError(field.to_string(), str.to_string(), e))?;
231 Ok(Duration::from_secs(secs))
232 }
233
234 pub fn convert_from_strings(
235 issued_for: &str,
236 signature: &str,
237 expires_at: &str,
238 issued_at: &str,
239 ) -> Result<Self, TrustError> {
240 let issued_for_bytes = Self::bs58_str_to_vec(issued_for, "issued_for")?;
242 let issued_for = PublicKey::decode(&issued_for_bytes)
243 .map_err(|e| DecodePublicKeyError(issued_for.to_string(), e))?;
244
245 let signature = Self::bs58_str_to_vec(signature, "signature")?;
247 let signature = Signature::decode(signature.to_vec())?;
248
249 let expires_at = Self::str_to_duration(expires_at, "expires_at")?;
251
252 let issued_at = Self::str_to_duration(issued_at, "issued_at")?;
254
255 Ok(Trust::new(issued_for, expires_at, issued_at, signature))
256 }
257}
258
259impl ToString for Trust {
260 fn to_string(&self) -> String {
261 let issued_for = bs58::encode(self.issued_for.encode()).into_string();
262 let signature = bs58::encode(self.signature.encode()).into_string();
263 let expires_at = self.expires_at.as_secs().to_string();
264 let issued_at = self.issued_at.as_secs().to_string();
265
266 format!("{issued_for}\n{signature}\n{expires_at}\n{issued_at}")
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 #[test]
275 fn test_gen_revoke_and_validate_ed25519() {
276 let truster = KeyPair::generate_ed25519();
277 let trusted = KeyPair::generate_ed25519();
278
279 let current = Duration::new(100, 0);
280 let duration = Duration::new(1000, 0);
281 let issued_at = Duration::new(10, 0);
282
283 let trust = Trust::create(&truster, trusted.public(), duration, issued_at);
284
285 assert_eq!(
286 Trust::verify(&trust, &truster.public(), current).is_ok(),
287 true
288 );
289 }
290
291 #[test]
292 fn test_validate_corrupted_revoke_ed25519() {
293 let truster = KeyPair::generate_ed25519();
294 let trusted = KeyPair::generate_ed25519();
295
296 let current = Duration::new(1000, 0);
297 let issued_at = Duration::new(10, 0);
298
299 let trust = Trust::create(&truster, trusted.public(), current, issued_at);
300
301 let corrupted_duration = Duration::new(1234, 0);
302 let corrupted_trust = Trust::new(
303 trust.issued_for,
304 trust.expires_at,
305 corrupted_duration,
306 trust.signature,
307 );
308
309 assert!(Trust::verify(&corrupted_trust, &truster.public(), current).is_err());
310 }
311
312 #[test]
313 fn test_encode_decode_ed25519() {
314 let truster = KeyPair::generate_ed25519();
315 let trusted = KeyPair::generate_ed25519();
316
317 let current = Duration::new(1000, 0);
318 let issued_at = Duration::new(10, 0);
319
320 let trust = Trust::create(&truster, trusted.public(), current, issued_at);
321
322 let encoded = trust.encode();
323 let decoded = Trust::decode(encoded.as_slice()).unwrap();
324
325 assert_eq!(trust, decoded);
326 }
327}