Secure Channels

Create end-to-end encrypted and mutually authenticated secure channels over any transport topology.

Now that we understand the basics of Nodes, Workers, and Routing ... let's create our first encrypted secure channel.

Establishing a secure channel requires establishing a shared secret key between the two entities that wish to communicate securely. This is usually achieved using a cryptographic key agreement protocol to safely derive a shared secret without transporting it over the network.

Running such protocols requires a stateful exchange of multiple messages and having a worker and routing system allows Ockam to hide the complexity of creating and maintaining a secure channel behind two simple functions:

  • create_secure_channel_listener(...) which waits for requests to create a secure channel.

  • create_secure_channel(...) which initiates the protocol to create a secure channel with a listener.

Responder node

Create a new file at:

touch examples/05-secure-channel-over-two-transport-hops-responder.rs

Add the following code to this file:

// examples/05-secure-channel-over-two-transport-hops-responder.rs
// This node starts a tcp listener, a secure channel listener, and an echoer worker.
// It then runs forever waiting for messages.

use hello_ockam::Echoer;
use ockam::identity::SecureChannelListenerOptions;
use ockam::tcp::{TcpListenerOptions, TcpTransportExtension};
use ockam::{node, Context, Result};

#[ockam::node]
async fn main(ctx: Context) -> Result<()> {
    // Create a node with default implementations
    let node = node(ctx).await?;

    // Initialize the TCP Transport.
    let tcp = node.create_tcp_transport()?;

    node.start_worker("echoer", Echoer)?;

    let bob = node.create_identity().await?;

    // Create a TCP listener and wait for incoming connections.
    let listener = tcp.listen("127.0.0.1:4000", TcpListenerOptions::new()).await?;

    // Create a secure channel listener for Bob that will wait for requests to
    // initiate an Authenticated Key Exchange.
    let secure_channel_listener = node.create_secure_channel_listener(
        &bob,
        "bob_listener",
        SecureChannelListenerOptions::new().as_consumer(listener.flow_control_id()),
    )?;

    // Allow access to the Echoer via Secure Channels
    node.flow_controls()
        .add_consumer(&"echoer".into(), secure_channel_listener.flow_control_id());

    // Don't call node.shutdown() here so this node runs forever.
    Ok(())
}

Middle node

Create a new file at:

Add the following code to this file:

Initiator node

Create a new file at:

Add the following code to this file:

Run

Run the responder in a separate terminal tab and keep it running:

Run the middle node in a separate terminal tab and keep it running:

Run the initiator:

Note the message flow.

Last updated

Was this helpful?