Examples + Fixing up Auth Interface to consume Connection

This commit is contained in:
Sarah Jamie Lewis 2021-01-12 01:52:27 -08:00
parent 96ae0b1352
commit d41663a3fe
5 changed files with 145 additions and 12 deletions

View File

@ -29,4 +29,5 @@ byteorder = "1.3.4"
socks = "0.3.3"
integer-encoding = "2.1.1"
secretbox = "0.1.2"
subtle = "2.3.0"
subtle = "2.3.0"
hashbrown = "0.9.1"

48
examples/simple_client.rs Normal file
View File

@ -0,0 +1,48 @@
use tapir::acns::tor::authentication::HashedPassword;
use ed25519_dalek::SecretKey;
use tapir::primitives::identity::Identity;
use tapir::connections::{OutboundConnection, Connection, InboundConnection, ConnectionInterface};
use tapir::primitives::transcript::Transcript;
use tapir::applications::authentication_app::{AuthenicationApp, AuthenticationCapability};
use tapir::connections::service::Service;
use rand::rngs::OsRng;
use tapir::acns::tor::TorProcess;
fn main() {
let mut auth_control_port = TorProcess::connect(9051)
.unwrap()
.authenticate(Box::new(HashedPassword::new(String::from("examplehashedpassword"))))
.unwrap();
let mut csprng = OsRng {};
let keypair = ed25519_dalek::Keypair::generate(&mut csprng);
match auth_control_port.add_onion_v3(SecretKey::from_bytes(&keypair.secret.to_bytes()).unwrap(), 9878, 10029) {
Ok(service_id) => {
// we authenticated!
let identity = Identity::initialize(keypair);
println!("Service Id: {}", service_id);
println!("Setup: {}", identity.hostname());
let mut service = Service::init(identity.clone());
let identity = identity.clone();
let outbound_identity = identity.clone();
let outbound_service = |mut conn: Connection<OutboundConnection>| {
let mut transcript = Transcript::new_transcript("tapir-transcript");
let mut auth_app = AuthenicationApp::new(outbound_identity);
match auth_app.run_outbound(conn, &mut transcript) {
Ok(conn) => {
println!("Authenticated {} {}", conn.hostname(), conn.has_capability(&AuthenticationCapability));
}
Err(err) => {
println!("Error: {:?}", err);
}
}
};
match service.connect("lzry2bfjkdzlx64aksxw5jpz6qdnvjoekpkzjqclpd4wz25dbv2pasid", outbound_service.clone()) {
_ => {}
}
loop {}
}
Err(err) => println!("{:?}", err),
}
}

47
examples/simple_server.rs Normal file
View File

@ -0,0 +1,47 @@
use tapir::acns::tor::authentication::HashedPassword;
use ed25519_dalek::SecretKey;
use tapir::primitives::identity::Identity;
use tapir::connections::{OutboundConnection, Connection, InboundConnection, ConnectionInterface};
use tapir::primitives::transcript::Transcript;
use tapir::applications::authentication_app::AuthenicationApp;
use tapir::connections::service::Service;
use rand::rngs::OsRng;
use tapir::acns::tor::TorProcess;
fn main() {
let mut auth_control_port = TorProcess::connect(9051)
.unwrap()
.authenticate(Box::new(HashedPassword::new(String::from("examplehashedpassword"))))
.unwrap();
let mut csprng = OsRng {};
let keypair = ed25519_dalek::Keypair::generate(&mut csprng);
match auth_control_port.add_onion_v3(SecretKey::from_bytes(&keypair.secret.to_bytes()).unwrap(), 9878, 10029) {
Ok(service_id) => {
// we authenticated!
let identity = Identity::initialize(keypair);
println!("Service Id: {}", service_id);
println!("Setup: {}", identity.hostname());
let service = Service::init(identity.clone());
let identity = identity.clone();
let inbound_service = |mut conn: Connection<InboundConnection>| {
let mut transcript = Transcript::new_transcript("tapir-transcript");
let mut auth_app = AuthenicationApp::new(identity);
match auth_app.run_inbound(conn, &mut transcript) {
Ok(conn) => {
println!("Authenticated Inbound Connection from {}", conn.hostname())
}
_ => {
println!("Failed Inbound Authentication")
}
}
};
let mut service = service.listen(10029, inbound_service.clone()).unwrap_or_else(|_| panic!());
loop {}
}
Err(err) => println!("{:?}", err),
}
}

View File

@ -1,6 +1,6 @@
use crate::applications::authentication_app::AuthenticationAppError::NotAuthenticatedError;
use crate::connections::utils::public_key_to_hostname;
use crate::connections::{Connection, ConnectionInterface, InboundConnection, OutboundConnection};
use crate::connections::{Connection, ConnectionInterface, InboundConnection, OutboundConnection, Capability};
use crate::primitives::identity::Identity;
use crate::primitives::transcript::Transcript;
use ed25519_dalek::PublicKey;
@ -8,7 +8,6 @@ use integer_encoding::VarInt;
use serde::Deserialize;
use serde::Serialize;
use sha3::Digest;
use std::io::Error;
use std::sync::Arc;
use subtle::ConstantTimeEq;
@ -21,6 +20,8 @@ pub enum AuthenticationAppError {
NotAuthenticatedError,
}
pub const AuthenticationCapability : Capability = Capability("AuthenticationCapability");
struct AuthenticationSession<Direction> {
long_term_identity: Arc<Identity>,
ephemeral_identity: Identity,
@ -35,7 +36,7 @@ struct AuthenticationSession<Direction> {
conn: Connection<Direction>,
}
impl<Direction> AuthenticationSession<Direction> {
impl<Direction> AuthenticationSession<Direction> where Direction:Clone {
pub fn new_outbound(mut conn: Connection<OutboundConnection>, long_term_identity: Arc<Identity>) -> AuthenticationSession<OutboundConnection> {
let ephemeral_identity = Identity::initialize_ephemeral_identity();
let mut auth_session = AuthenticationSession {
@ -96,7 +97,7 @@ impl<Direction> AuthenticationSession<Direction> {
}
/// check the challenge from the remote
fn check_remote_challenge(&mut self) -> Result<(), AuthenticationAppError> {
fn check_remote_challenge(&mut self) -> Result<Connection<Direction>, AuthenticationAppError> {
match self.conn.send_encrypted(self.generate_challenge_message()) {
Ok(()) => {
let remote_challenge = self.conn.expect_encrypted();
@ -104,7 +105,9 @@ impl<Direction> AuthenticationSession<Direction> {
cmp_challenge.extend_from_slice(self.challenge.as_slice());
cmp_challenge.extend_from_slice(public_key_to_hostname(&self.remote_long_term_identity).as_bytes());
if remote_challenge.ct_eq(cmp_challenge.as_slice()).unwrap_u8() == 1 {
return Ok(());
self.conn.set_hostname(&public_key_to_hostname(&self.remote_long_term_identity));
self.conn.set_capability(&AuthenticationCapability);
return Ok(self.conn.try_clone());
}
self.conn.shutdown();
Err(NotAuthenticatedError)
@ -115,7 +118,7 @@ impl<Direction> AuthenticationSession<Direction> {
}
impl AuthenticationSession<OutboundConnection> {
pub fn generate_challenge(&mut self, transcript: &mut Transcript) -> Result<(), AuthenticationAppError> {
pub fn generate_challenge(&mut self, transcript: &mut Transcript) -> Result<Connection<OutboundConnection>, AuthenticationAppError> {
let l2e = self.long_term_identity.edh(self.remote_ephemeral_identity);
let e2l = self.ephemeral_identity.edh(self.remote_long_term_identity);
let e2e = self.ephemeral_identity.edh(self.remote_ephemeral_identity);
@ -140,7 +143,7 @@ impl AuthenticationSession<OutboundConnection> {
}
impl AuthenticationSession<InboundConnection> {
pub fn generate_challenge(&mut self, transcript: &mut Transcript) -> Result<(), AuthenticationAppError> {
pub fn generate_challenge(&mut self, transcript: &mut Transcript) -> Result<Connection<InboundConnection>, AuthenticationAppError> {
let l2e = self.long_term_identity.edh(self.remote_ephemeral_identity);
let e2l = self.ephemeral_identity.edh(self.remote_long_term_identity);
let e2e = self.ephemeral_identity.edh(self.remote_ephemeral_identity);
@ -177,13 +180,13 @@ impl AuthenicationApp {
AuthenicationApp { identity }
}
pub fn run_outbound(&mut self, conn: &mut Connection<OutboundConnection>, transcript: &mut Transcript) -> Result<(), AuthenticationAppError> {
let mut auth_session = AuthenticationSession::<OutboundConnection>::new_outbound(conn.try_clone(), self.identity.clone());
pub fn run_outbound(&mut self, conn: Connection<OutboundConnection>, transcript: &mut Transcript) -> Result<Connection<OutboundConnection>, AuthenticationAppError> {
let mut auth_session = AuthenticationSession::<OutboundConnection>::new_outbound(conn, self.identity.clone());
auth_session.generate_challenge(transcript)
}
pub fn run_inbound(&mut self, conn: &mut Connection<InboundConnection>, transcript: &mut Transcript) -> Result<(), AuthenticationAppError> {
let mut auth_session = AuthenticationSession::<InboundConnection>::new_inbound(conn.try_clone(), self.identity.clone());
pub fn run_inbound(&mut self, conn: Connection<InboundConnection>, transcript: &mut Transcript) -> Result<Connection<InboundConnection>, AuthenticationAppError> {
let mut auth_session = AuthenticationSession::<InboundConnection>::new_inbound(conn, self.identity.clone());
auth_session.generate_challenge(transcript)
}
}

View File

@ -3,6 +3,7 @@ use secretbox::CipherType::Salsa20;
use secretbox::SecretBox;
use std::io::{Error, Read, Write};
use std::net::{Shutdown, TcpStream};
use hashbrown::HashSet;
/// Connections provides an interface for manage sets of connections on top of a particular
/// ACN.
@ -21,22 +22,41 @@ pub struct InboundConnection(());
#[derive(Clone)]
pub struct OutboundConnection(());
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Capability(pub &'static str);
pub struct Connection<Direction> {
conn: TcpStream,
direction: Direction,
key: Vec<u8>,
hostname: String,
capabilities: HashSet<Capability>
}
pub trait ConnectionInterface {
fn set_hostname(&mut self, hostname: &String);
fn hostname(&self) -> String;
fn enable_encryption(&mut self, key: Vec<u8>);
fn send(&mut self, amsg: &String) -> Result<(), Error>;
fn send_encrypted(&mut self, msg: Vec<u8>) -> Result<(), Error>;
fn expect_encrypted(&mut self) -> Vec<u8>;
fn expect(&mut self) -> Result<Vec<u8>, Error>;
fn shutdown(&mut self);
fn set_capability(&mut self, capability: &Capability);
fn has_capability(&self, capability: &Capability) -> bool;
}
impl<Direction> ConnectionInterface for Connection<Direction> {
fn set_hostname(&mut self, hostname: &String) {
self.hostname = hostname.clone()
}
fn hostname(&self) -> String {
self.hostname.clone()
}
fn enable_encryption(&mut self, key: Vec<u8>) {
self.key = key
}
@ -111,6 +131,14 @@ impl<Direction> ConnectionInterface for Connection<Direction> {
_ => {} // If anything bad happens we will know soon enough...
}
}
fn set_capability(&mut self, capability: &Capability) {
self.capabilities.insert(capability.clone());
}
fn has_capability(&self, capability: &Capability) -> bool {
self.capabilities.contains(capability)
}
}
impl<Direction> Connection<Direction>
@ -122,6 +150,8 @@ where
conn,
direction: InboundConnection(()),
key: vec![],
hostname: String::new(),
capabilities: HashSet::new()
}
}
@ -130,6 +160,8 @@ where
conn,
direction: OutboundConnection(()),
key: vec![],
hostname: String::new(),
capabilities: HashSet::new()
}
}
@ -138,6 +170,8 @@ where
conn: self.conn.try_clone().unwrap(),
direction: self.direction.clone(),
key: self.key.clone(),
hostname: self.hostname.clone(),
capabilities: self.capabilities.clone()
}
}
}