1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Based on Duncan's fantastic
//! [Scuttlebutt Protocol Guide](https://ssbc.github.io/scuttlebutt-protocol-guide/)
//! ([repo](https://github.com/ssbc/scuttlebutt-protocol-guide)),
//! which he graciously released into the public domain.
#![cfg_attr(not(feature = "std"), no_std)]

mod bytes;
mod error;
pub use error::HandshakeError;
mod crypto;

#[cfg(feature = "std")]
mod util;

#[cfg(feature = "std")]
#[path = ""]
mod std_stuff {
    mod client;
    pub use client::client_side;
    mod server;
    pub use server::server_side;
}
#[cfg(feature = "std")]
pub use std_stuff::*;

pub mod sync;

#[cfg(all(test, feature = "std"))]
mod tests {
    use super::*;
    use std::io::ErrorKind;

    use futures::executor::block_on;
    use futures::future::join;

    extern crate async_ringbuffer;
    use async_ringbuffer::Duplex;
    use ssb_crypto::{Keypair, NetworkKey, PublicKey};

    #[test]
    fn basic() {
        let (mut c_stream, mut s_stream) = Duplex::pair(1024);
        let skey = Keypair::generate();
        let ckey = Keypair::generate();

        let net_key = NetworkKey::SSB_MAIN_NET;
        let client_side = client_side(&mut c_stream, &net_key, &ckey, &skey.public);
        let server_side = server_side(&mut s_stream, &net_key, &skey);

        let (c_out, s_out) = block_on(async { join(client_side, server_side).await });

        let c_out = c_out.unwrap();
        let s_out = s_out.unwrap();

        assert_eq!(c_out.write_key.0, s_out.read_key.0);
        assert_eq!(c_out.read_key.0, s_out.write_key.0);

        assert_eq!(c_out.write_starting_nonce.0, s_out.read_starting_nonce.0);
        assert_eq!(c_out.read_starting_nonce.0, s_out.write_starting_nonce.0);
    }

    fn is_eof_err<T>(r: &Result<T, HandshakeError<std::io::Error>>) -> bool {
        match r {
            Err(HandshakeError::Io(e)) => e.kind() == ErrorKind::UnexpectedEof,
            _ => false,
        }
    }

    #[test]
    fn server_rejects_wrong_netkey() {
        let (mut c_stream, mut s_stream) = Duplex::pair(1024);
        let skey = Keypair::generate();
        let ckey = Keypair::generate();

        let cnet = NetworkKey::generate();
        let snet = NetworkKey::generate();

        let client = client_side(&mut c_stream, &cnet, &ckey, &skey.public);
        let server = server_side(&mut s_stream, &snet, &skey);

        let (c_out, s_out) = block_on(async { join(client, server).await });

        assert!(is_eof_err(&c_out));
        match s_out {
            Err(HandshakeError::ClientHelloVerifyFailed) => {}
            _ => panic!(),
        };
    }

    #[test]
    fn server_rejects_wrong_pk() {
        test_handshake_with_bad_server_pk(&PublicKey([0; 32]));

        let key = Keypair::generate();
        test_handshake_with_bad_server_pk(&key.public);
    }

    fn test_handshake_with_bad_server_pk(bad_pk: &PublicKey) {
        let (mut c_stream, mut s_stream) = Duplex::pair(1024);
        let skey = Keypair::generate();
        let ckey = Keypair::generate();

        let net_key = NetworkKey::SSB_MAIN_NET;

        let client_side = client_side(&mut c_stream, &net_key, &ckey, &bad_pk);
        let server_side = server_side(&mut s_stream, &net_key, &skey);

        let (c_out, s_out) = block_on(async { join(client_side, server_side).await });

        assert!(c_out.is_err());
        assert!(s_out.is_err());
    }
}