confitul/
remote_host.rs

1use crate::crypto::verify;
2use crate::Host;
3use crate::HostInfo;
4use ed25519_dalek;
5use std::convert::TryFrom;
6use std::fmt::Formatter;
7
8/// A remote host, for which this program instance is not responsible.
9///
10/// Typically, this is a host about which we gathered informations,
11/// but it is not local so, among other things, we can not really trust
12/// it and we do not have its private key.
13///
14/// This should *NOT* be serialized as it is not trustable. Instead,
15/// de-serialize from the HostInfo struct then call the constructor,
16/// which checks for integrity.
17#[derive(Debug)]
18pub struct RemoteHost {
19    info: HostInfo,
20    pubkey: ed25519_dalek::PublicKey,
21}
22
23impl RemoteHost {
24    /// Create a new remote host.
25    ///
26    /// The typical way to build this is from host info which has been
27    /// serialized, sent over the wire, then de-serialized into a host info.
28    ///
29    /// # Examples
30    /// ```
31    /// use confitul::LocalHost;
32    /// use confitul::RemoteHost;
33    /// use confitul::Host;
34    ///
35    /// let lh = LocalHost::new(None).unwrap();
36    /// let rh = RemoteHost::new(&lh.info()).unwrap();
37    /// print!("{}\n{}\n", lh, rh);
38    /// ```
39    pub fn new(info: &HostInfo) -> Result<RemoteHost, signature::Error> {
40        let pubkey = ed25519_dalek::PublicKey::try_from(info.id)?;
41        let remote_host = RemoteHost {
42            info: info.clone(),
43            pubkey,
44        };
45        match &info.sig {
46            Some(_) => {}
47            None => return Err(signature::Error::new()),
48        }
49        print!("{:?}\n", remote_host.info.sig.as_ref().unwrap());
50        print!("{:?}\n", info.sig.as_ref().unwrap());
51        remote_host.verify_self()?;
52        Ok(remote_host)
53    }
54}
55
56impl Host for RemoteHost {
57    fn info(&self) -> &HostInfo {
58        &self.info
59    }
60    fn verify_msg(&self, msg: &[u8], sig: &[u8]) -> Result<(), signature::Error> {
61        verify(&self.pubkey, msg, sig)
62    }
63}
64
65impl std::fmt::Display for RemoteHost {
66    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
67        write!(f, "{{\"type\":\"remote\",\"info\":{}}}", self.info)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::Host;
74    use super::HostInfo;
75    use super::RemoteHost;
76    use crate::LocalHost;
77    use serde_json;
78
79    #[test]
80    fn test_remote_host_serde_json() {
81        let local_host = LocalHost::new(None).unwrap();
82        let serialized = serde_json::to_string(local_host.info()).unwrap();
83        let deserialized: HostInfo = serde_json::from_str(&serialized).unwrap();
84        assert_eq!(local_host.info(), &deserialized);
85        let remote_host = RemoteHost::new(&deserialized).unwrap();
86        assert!(matches!(remote_host.verify_self(), Ok(())));
87
88        let msg = "this is the message".as_bytes();
89        let sig = local_host.sign_msg(msg);
90        assert!(matches!(remote_host.verify_msg(msg, &sig), Ok(())));
91    }
92}