Skip to content

Commit

Permalink
Add more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
voidc committed Feb 22, 2021
1 parent a8d5aa5 commit 08ba594
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/daemon/rps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl SocketRpsModule {
.find(|(m, _)| *m == Module::Onion)
.ok_or_else(|| anyhow!("Peer does not expose onion port"))?;
let peer_addr = SocketAddr::new(peer_addr, *peer_port);
let peer_hostkey = RsaPublicKey::new(peer_hostkey.as_ref());
let peer_hostkey = RsaPublicKey::from_raw_bytes(peer_hostkey.as_ref());
Ok(Peer::new(peer_addr, peer_hostkey))
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ pub use crate::onion::*;
pub type Result<T> = std::result::Result<T, anyhow::Error>;

/// A remote peer characterized by its address, the port on which it is listening for onion
/// connections and its public key. The public key is needed to verify the authenticity of
/// signed messages received from this peer.
/// connections and its public key.
///
/// The public key is needed to verify the authenticity of signed messages received from this peer.
#[derive(Clone)]
pub struct Peer {
addr: SocketAddr,
Expand All @@ -85,12 +86,16 @@ impl fmt::Debug for Peer {
}
}

/// A stream of [`Peer`]s used for constructing tunnels.
///
/// It is up to the user to choose an appropriate peer sampling and caching strategy.
#[derive(Clone)]
pub struct PeerProvider {
inner: mpsc::Sender<oneshot::Sender<Peer>>,
}

impl PeerProvider {
/// Turns a given stream of [`Peer`]s into a [`PeerProvider`].
pub fn from_stream<S>(mut stream: S) -> Self
where
S: Stream<Item = Peer> + Unpin + Send + Sync + 'static,
Expand Down
53 changes: 49 additions & 4 deletions src/onion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ const INCOMING_BUFFER_SIZE: usize = 100;

static TUNNEL_COUNT: AtomicUsize = AtomicUsize::new(0);

/// A tunnel endpoint. This type persists over tunnel reconstructions.
///
/// Use [`OnionContext::build_tunnel`] to build a new tunnel.
///
/// We differentiate persistent and ephemeral tunnels.
/// A persistent tunnel is characterized only by its ID and its endpoints, while an ephemeral
/// tunnel is specific to the intermediate hops.
/// As a user, you will only deal with persistent tunnels, which forward data to and from
/// periodically rebuilt ephemeral tunnels.
pub struct Tunnel {
tunnel_id: TunnelId,
data_tx: mpsc::UnboundedSender<Bytes>,
Expand All @@ -59,13 +68,21 @@ impl Tunnel {
(tunnel, data_tx2, data_rx2)
}

/// Receive data from the remote peer.
///
/// Returns an error if the connection was closed.
pub async fn read(&mut self) -> Result<Bytes> {
self.data_rx
.recv()
.await
.ok_or(anyhow!("Connection closed."))
}

/// Send data to the remote peer.
///
/// The data may be split across multiple messages if it is too large to fit into a single one.
///
/// Returns an error if the connection was closed.
pub fn write(&self, mut buf: Bytes) -> Result<()> {
while !buf.is_empty() {
let part = buf.split_to(cmp::min(protocol::MAX_DATA_SIZE, buf.len()));
Expand All @@ -76,10 +93,12 @@ impl Tunnel {
Ok(())
}

/// Returns the unique id of this tunnel.
pub fn id(&self) -> TunnelId {
self.tunnel_id
}

/// Create an additional write handle to this tunnel.
pub fn writer(&self) -> TunnelWriter {
TunnelWriter {
tunnel_id: self.tunnel_id,
Expand Down Expand Up @@ -122,6 +141,11 @@ impl Drop for Tunnel {
}
}

/// A write handle to a [`Tunnel`].
///
/// Each tunnel may have arbitrarily many [`TunnelWriter`]s.
/// This is useful because this type implements [`Clone`], [`Send`] and [`Sync`] and can thus
/// safely be shared across threads.
#[derive(Clone)]
pub struct TunnelWriter {
tunnel_id: TunnelId,
Expand Down Expand Up @@ -152,6 +176,10 @@ impl fmt::Debug for TunnelWriter {
}
}

/// A handle to the underlying onion router allowing the construction of new tunnels.
///
/// Use [`OnionBuilder`] to configure and start a new onion router instance.
/// This type implements [`Clone`], [`Send`] and [`Sync`], so it can be shared across threads.
#[derive(Clone)]
pub struct OnionContext {
peer_provider: PeerProvider,
Expand Down Expand Up @@ -193,8 +221,7 @@ impl OnionContext {
ctx
}

/// Builds a new tunnel to `dest` over `n_hops` additional peers.
/// Performs a handshake with each hop and then spawns a task for handling incoming messages
/// Builds a new tunnel to `dest`.
pub async fn build_tunnel(&self, dest: Peer) -> Result<Tunnel> {
self.build_tunnel_internal(Target::Peer(dest)).await
}
Expand All @@ -219,6 +246,7 @@ impl OnionContext {
ready_rx.await?
}

/// Send cover data with a fake payload of the given size.
pub fn send_cover(&self, size: u16) -> Result<()> {
let packet_count = (size as usize + protocol::MAX_DATA_SIZE - 1) / protocol::MAX_DATA_SIZE;
for _ in 0..packet_count {
Expand Down Expand Up @@ -278,11 +306,13 @@ impl CoverHandler {
}
}

/// A stream of incoming tunnel connections.
pub struct OnionIncoming {
incoming: mpsc::Receiver<Tunnel>,
}

impl OnionIncoming {
/// Returns a [`Tunnel`] handle once a new incoming connection is made.
pub async fn next(&mut self) -> Option<Tunnel> {
self.incoming.recv().await
}
Expand Down Expand Up @@ -418,6 +448,7 @@ impl RoundHandler {
}
}

/// Used for configuring and starting new onion router instances.
pub struct OnionBuilder {
listen_addr: SocketAddr,
hostkey: RsaPrivateKey,
Expand All @@ -428,7 +459,8 @@ pub struct OnionBuilder {
}

impl OnionBuilder {
/// Construct a new onion instance.
/// Initialized the construction of a new onion router instance.
///
/// Returns a builder which allows further configuration.
pub fn new(
listen_addr: SocketAddr,
Expand All @@ -445,22 +477,35 @@ impl OnionBuilder {
}
}

/// Sets whether cover traffic should be enabled.
///
/// If cover traffic is disabled all calls to [`OnionContext::send_cover`] will fail.
/// The default value is true.
pub fn enable_cover_traffic(mut self, enable: bool) -> Self {
self.enable_cover = enable;
self
}

/// Sets the number of additional hops per tunnel, not counting the two endpoints.
///
/// The default value is 2.
pub fn set_hops_per_tunnel(mut self, n_hops: usize) -> Self {
self.n_hops = n_hops;
self
}

/// Sets the amount of time after which tunnels will be rebuilt.
///
/// The default value is 30 seconds.
pub fn set_round_duration(mut self, dur: Duration) -> Self {
self.round_duration = dur;
self
}

/// Returns the constructed instance.
/// Starts the onion router.
///
/// Returns a [`OnionContext`] handle used for building new tunnels and a stream of incoming
/// connections [`OnionIncoming`].
pub fn start(self) -> (OnionContext, OnionIncoming) {
let OnionBuilder {
listen_addr,
Expand Down
17 changes: 14 additions & 3 deletions src/onion/crypto/crypto_openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ pub(crate) const SIGNATURE_LEN: usize = 512;

pub(crate) struct EphemeralPrivateKey(pkey::PKey<pkey::Private>);
pub(crate) struct EphemeralPublicKey(Bytes);

/// A RSA public key.
#[derive(Clone)]
pub struct RsaPublicKey(Bytes);

/// A RSA private key.
pub struct RsaPrivateKey(pkey::PKey<pkey::Private>);

pub(crate) struct SessionKey([u8; AES_128_CTR_KEY_LEN]);
// TODO consider storing generic B: AsRef<[u8]> instead of Bytes (-> avoid allocations)

pub(crate) fn fill_random(buf: &mut [u8]) {
rand::rand_bytes(buf).unwrap()
Expand Down Expand Up @@ -64,6 +68,7 @@ pub(crate) fn generate_ephemeral_keypair() -> (EphemeralPrivateKey, EphemeralPub

impl RsaPrivateKey {
/// Reads a RSA private key from the specified file.
///
/// The key is expected to be in the DER format and PEM encoded.
pub fn from_pem_file<P: AsRef<Path>>(path: P) -> Result<RsaPrivateKey> {
let mut file = File::open(path)?;
Expand All @@ -73,6 +78,7 @@ impl RsaPrivateKey {
Ok(RsaPrivateKey(pkey))
}

/// Computes the corresponding public key.
pub fn public_key(&self) -> RsaPublicKey {
RsaPublicKey(self.0.public_key_to_der().unwrap().into())
}
Expand All @@ -85,11 +91,16 @@ impl RsaPrivateKey {
}

impl RsaPublicKey {
pub fn new(bytes: &[u8]) -> Self {
/// Creates a RSA public key from the given data.
///
/// The data is expected to be a DER encoded key in the RSAPublicKey format.
pub fn from_raw_bytes(bytes: &[u8]) -> Self {
Self(bytes.to_vec().into())
}

/// Converts a RSA public key from the SubjectPublicKeyInfo format
/// Creates a RSA public key from the given data.
///
/// The data is expected to be a DER encoded key in the SubjectPublicKeyInfo format.
pub fn from_subject_info(bytes: &[u8]) -> Self {
Self(bytes.to_vec().into())
}
Expand Down
16 changes: 14 additions & 2 deletions src/onion/crypto/crypto_ring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ pub(crate) const KEY_LEN: usize = 32;

pub(crate) struct EphemeralPrivateKey(agreement::EphemeralPrivateKey);
pub(crate) struct EphemeralPublicKey(agreement::UnparsedPublicKey<Bytes>);

/// A RSA public key.
#[derive(Clone)]
pub struct RsaPublicKey(signature::UnparsedPublicKey<Bytes>);

/// A RSA private key.
pub struct RsaPrivateKey(signature::RsaKeyPair);

pub(crate) struct SessionKey(aead::LessSafeKey);
// TODO consider storing generic B: AsRef<[u8]> instead of Bytes (-> avoid allocations)

Expand Down Expand Up @@ -68,6 +73,7 @@ pub(crate) fn generate_ephemeral_keypair() -> (EphemeralPrivateKey, EphemeralPub

impl RsaPrivateKey {
/// Reads a RSA private key from the specified file.
///
/// The key is expected to be in the DER format and PEM encoded.
pub fn from_pem_file<P: AsRef<Path>>(path: P) -> Result<RsaPrivateKey> {
let file = BufReader::new(File::open(path)?);
Expand All @@ -81,6 +87,7 @@ impl RsaPrivateKey {
Ok(RsaPrivateKey(signature::RsaKeyPair::from_der(&bytes)?))
}

/// Computes the corresponding public key.
pub fn public_key(&self) -> RsaPublicKey {
let public_key_bytes = self.0.public_key().as_ref().to_vec().into();
let public_key = signature::UnparsedPublicKey::new(
Expand All @@ -102,15 +109,20 @@ impl RsaPrivateKey {
}

impl RsaPublicKey {
pub fn new(bytes: &[u8]) -> Self {
/// Creates a RSA public key from the given data.
///
/// The data is expected to be a DER encoded key in the RSAPublicKey format.
pub fn from_raw_bytes(bytes: &[u8]) -> Self {
let public_key = signature::UnparsedPublicKey::new(
&signature::RSA_PKCS1_2048_8192_SHA256,
bytes.to_vec().into(),
);
RsaPublicKey(public_key)
}

/// Converts a RSA public key from the SubjectPublicKeyInfo format
/// Creates a RSA public key from the given data.
///
/// The data is expected to be a DER encoded key in the SubjectPublicKeyInfo format.
pub fn from_subject_info(bytes: &[u8]) -> Self {
Self::new(&bytes[24..])
}
Expand Down
1 change: 1 addition & 0 deletions src/onion/tunnel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use tokio::sync::{broadcast, mpsc, oneshot, Mutex};

const MAX_PEER_FAILURES: usize = 10;

/// The unique ID of a tunnel.
pub type TunnelId = u32;

#[derive(Error, Debug)]
Expand Down

0 comments on commit 08ba594

Please sign in to comment.