Browse Source

Merge #459

459: Authentication r=rishflab a=rishflab

#229 


Co-authored-by: rishflab <rishflab@hotmail.com>
burn-down-handle
bors[bot] 3 years ago
committed by GitHub
parent
commit
95ebf242c0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      .github/workflows/ci.yml
  2. 1
      Cargo.lock
  3. 1
      daemon/Cargo.toml
  4. 16
      daemon/src/connection.rs
  5. 10
      daemon/src/maker.rs
  6. 11
      daemon/src/maker_inc_connections.rs
  7. 31
      daemon/src/noise.rs
  8. 10
      daemon/src/seed.rs
  9. 13
      daemon/src/taker.rs
  10. 26
      daemon/tests/harness/mod.rs
  11. 3
      start_all.sh

9
.github/workflows/ci.yml

@ -76,10 +76,13 @@ jobs:
- name: Smoke test ${{ matrix.os }} binary
shell: bash
run: |
target/debug/maker --data-dir=/tmp/maker --generate-seed testnet &
sleep 10s # Wait for maker to start
mkdir -p /tmp/maker/testnet
cp -r daemon/util/testnet_seeds/maker_seed /tmp/maker/testnet/maker_seed
target/debug/maker --data-dir=/tmp/maker testnet &
sleep 10s # Wait for maker to start\
target/debug/taker --data-dir=/tmp/taker --generate-seed testnet &
# The maker-id is generated from the makers seed found in daemon/util/testnet_seeds/maker_seed
target/debug/taker --data-dir=/tmp/taker --generate-seed --maker-id 10d4ba2ac3f7a22da4009d813ff1bc3f404dfe2cc93a32bedf1512aa9951c95e testnet &
sleep 10s # Wait for taker to start
curl --fail http://localhost:8000/api/alive

1
Cargo.lock

@ -672,6 +672,7 @@ dependencies = [
"tracing-subscriber",
"uuid",
"vergen",
"x25519-dalek",
"xtra",
"xtra_productivity",
]

1
daemon/Cargo.toml

@ -42,6 +42,7 @@ tokio-util = { version = "0.6", features = ["codec"] }
tracing = { version = "0.1" }
tracing-subscriber = { version = "0.2", default-features = false, features = ["fmt", "ansi", "env-filter", "chrono", "tracing-log", "json"] }
uuid = { version = "0.8", features = ["serde", "v4"] }
x25519-dalek = { version = "1.1" }
xtra = { version = "0.6", features = ["with-tokio-1"] }
xtra_productivity = { path = "../xtra_productivity" }

16
daemon/src/connection.rs

@ -17,12 +17,20 @@ pub struct Actor {
}
impl Actor {
pub async fn new(maker: SocketAddr) -> Result<Self> {
pub async fn new(
maker_addr: SocketAddr,
maker_noise_static_pk: x25519_dalek::PublicKey,
noise_static_sk: x25519_dalek::StaticSecret,
) -> Result<Self> {
let (read, write, noise) = loop {
let socket = tokio::net::TcpSocket::new_v4().expect("Be able ta create a socket");
if let Ok(mut connection) = socket.connect(maker).await {
let noise = noise::initiator_handshake(&mut connection).await?;
if let Ok(mut connection) = socket.connect(maker_addr).await {
let noise = noise::initiator_handshake(
&mut connection,
&noise_static_sk,
&maker_noise_static_pk,
)
.await?;
let (read, write) = connection.into_split();
break (read, write, Arc::new(Mutex::new(noise)));
} else {

10
daemon/src/maker.rs

@ -198,10 +198,14 @@ async fn main() -> Result<()> {
let auth_password = seed.derive_auth_password::<auth::Password>();
let noise_static_sk = seed.derive_noise_static_secret();
let noise_static_pk = x25519_dalek::PublicKey::from(&noise_static_sk);
tracing::info!(
"Authentication details: username='{}' password='{}'",
"Authentication details: username='{}' password='{}', noise_public_key='{}'",
MAKER_USERNAME,
auth_password
auth_password,
hex::encode(noise_static_pk.to_bytes())
);
// TODO: Actually fetch it from Olivia
@ -264,7 +268,7 @@ async fn main() -> Result<()> {
monitor::Actor::new(electrum, channel, cfds)
}
},
|channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1),
|channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1, noise_static_sk),
time::Duration::hours(opts.settlement_time_interval_hours as i64),
)
.await?;

11
daemon/src/maker_inc_connections.rs

@ -67,17 +67,20 @@ pub struct Actor {
write_connections: HashMap<TakerId, Address<send_to_socket::Actor<wire::MakerToTaker>>>,
new_taker_channel: Box<dyn MessageChannel<NewTakerOnline>>,
taker_msg_channel: Box<dyn MessageChannel<FromTaker>>,
noise_priv_key: x25519_dalek::StaticSecret,
}
impl Actor {
pub fn new(
new_taker_channel: Box<dyn MessageChannel<NewTakerOnline>>,
taker_msg_channel: Box<dyn MessageChannel<FromTaker>>,
noise_priv_key: x25519_dalek::StaticSecret,
) -> Self {
Self {
write_connections: HashMap::new(),
new_taker_channel: new_taker_channel.clone_channel(),
taker_msg_channel: taker_msg_channel.clone_channel(),
noise_priv_key,
}
}
@ -96,14 +99,16 @@ impl Actor {
async fn handle_new_connection_impl(
&mut self,
mut stream: TcpStream,
address: SocketAddr,
taker_address: SocketAddr,
_: &mut Context<Self>,
) -> Result<()> {
let taker_id = TakerId::default();
tracing::info!("New taker {} connected on {}", taker_id, address);
tracing::info!("New taker {} connected on {}", taker_id, taker_address);
let noise = Arc::new(Mutex::new(noise::responder_handshake(&mut stream).await?));
let noise = Arc::new(Mutex::new(
noise::responder_handshake(&mut stream, &self.noise_priv_key).await?,
));
let (read, write) = stream.into_split();
let read = FramedRead::new(read, wire::EncryptedJsonCodec::new(noise.clone()))

31
daemon/src/noise.rs

@ -6,15 +6,19 @@ use tokio::net::TcpStream;
pub static NOISE_MAX_MSG_LEN: u32 = 65535;
pub static NOISE_TAG_LEN: u32 = 16;
// TODO: investigate what these params do and whether we can use get authentication for free using
// them
static NOISE_PARAMS: &str = "Noise_XX_25519_ChaChaPoly_BLAKE2s";
static NOISE_PARAMS: &str = "Noise_IK_25519_ChaChaPoly_BLAKE2s";
pub async fn initiator_handshake(connection: &mut TcpStream) -> Result<TransportState> {
pub async fn initiator_handshake(
connection: &mut TcpStream,
local_priv_key: &x25519_dalek::StaticSecret,
remote_pub_key: &x25519_dalek::PublicKey,
) -> Result<TransportState> {
let builder: Builder<'_> = Builder::new(NOISE_PARAMS.parse()?);
let static_key = builder.generate_keypair()?.private;
let mut noise = builder.local_private_key(&static_key).build_initiator()?;
let mut noise = builder
.local_private_key(&local_priv_key.to_bytes())
.remote_public_key(&remote_pub_key.to_bytes())
.build_initiator()?;
let mut buf = vec![0u8; NOISE_MAX_MSG_LEN as usize];
@ -23,9 +27,6 @@ pub async fn initiator_handshake(connection: &mut TcpStream) -> Result<Transport
noise.read_message(&recv(connection).await?, &mut buf)?;
let len = noise.write_message(&[], &mut buf)?;
send(connection, &buf[..len]).await?;
let noise = noise.into_transport_mode()?;
tracing::debug!("Noise protocol initiator handshake is complete");
@ -33,11 +34,15 @@ pub async fn initiator_handshake(connection: &mut TcpStream) -> Result<Transport
Ok(noise)
}
pub async fn responder_handshake(connection: &mut TcpStream) -> Result<TransportState> {
pub async fn responder_handshake(
connection: &mut TcpStream,
local_priv_key: &x25519_dalek::StaticSecret,
) -> Result<TransportState> {
let builder: Builder<'_> = Builder::new(NOISE_PARAMS.parse()?);
let static_key = builder.generate_keypair()?.private;
let mut noise = builder.local_private_key(&static_key).build_responder()?;
let mut noise = builder
.local_private_key(&local_priv_key.to_bytes())
.build_responder()?;
let mut buf = vec![0u8; NOISE_MAX_MSG_LEN as usize];
@ -46,8 +51,6 @@ pub async fn responder_handshake(connection: &mut TcpStream) -> Result<Transport
let len = noise.write_message(&[0u8; 0], &mut buf)?;
send(connection, &buf[..len]).await?;
noise.read_message(&recv(connection).await?, &mut buf)?;
let noise = noise.into_transport_mode()?;
tracing::debug!("Noise protocol responder handshake is complete");

10
daemon/src/seed.rs

@ -72,6 +72,16 @@ impl Seed {
P::from(password)
}
pub fn derive_noise_static_secret(&self) -> x25519_dalek::StaticSecret {
let mut secret = [0u8; 32];
Hkdf::<Sha256>::new(None, &self.0)
.expand(b"NOISE_STATIC_SECRET", &mut secret)
.expect("okm array is of correct length");
x25519_dalek::StaticSecret::from(secret)
}
}
impl Default for Seed {

13
daemon/src/taker.rs

@ -31,6 +31,10 @@ struct Opts {
#[clap(long, default_value = "127.0.0.1:9999")]
maker: SocketAddr,
/// The public key of the maker as a 32 byte hex string.
#[clap(long, parse(try_from_str = parse_x25519_pubkey))]
maker_id: x25519_dalek::PublicKey,
/// The IP address to listen on for the HTTP API.
#[clap(long, default_value = "127.0.0.1:8000")]
http_address: SocketAddr,
@ -51,6 +55,12 @@ struct Opts {
network: Network,
}
fn parse_x25519_pubkey(s: &str) -> Result<x25519_dalek::PublicKey> {
let mut bytes = [0u8; 32];
hex::decode_to_slice(s, &mut bytes)?;
Ok(x25519_dalek::PublicKey::from(bytes))
}
#[derive(Parser)]
enum Network {
Mainnet {
@ -153,6 +163,7 @@ async fn main() -> Result<()> {
let bitcoin_network = opts.network.bitcoin_network();
let ext_priv_key = seed.derive_extended_priv_key(bitcoin_network)?;
let noise_static_sk = seed.derive_noise_static_secret();
let wallet = wallet::Actor::new(
opts.network.electrum(),
@ -219,7 +230,7 @@ async fn main() -> Result<()> {
let connection::Actor {
send_to_maker,
read_from_maker,
} = connection::Actor::new(opts.maker).await?;
} = connection::Actor::new(opts.maker, opts.maker_id, noise_static_sk).await?;
let TakerActorSystem {
cfd_actor_addr,

26
daemon/tests/harness/mod.rs

@ -5,6 +5,7 @@ use crate::schnorrsig;
use daemon::maker_cfd::CfdAction;
use daemon::model::cfd::{Cfd, Order};
use daemon::model::Usd;
use daemon::seed::Seed;
use daemon::{connection, db, maker_cfd, maker_inc_connections, taker_cfd};
use sqlx::SqlitePool;
use std::net::SocketAddr;
@ -25,7 +26,7 @@ pub async fn start_both() -> (Maker, Taker) {
.unwrap();
let maker = Maker::start(oracle_pk).await;
let taker = Taker::start(oracle_pk, maker.listen_addr).await;
let taker = Taker::start(oracle_pk, maker.listen_addr, maker.noise_static_pk).await;
(maker, taker)
}
@ -41,6 +42,7 @@ pub struct Maker {
pub inc_conn_actor_addr: xtra::Address<maker_inc_connections::Actor>,
pub listen_addr: SocketAddr,
pub mocks: mocks::Mocks,
pub noise_static_pk: x25519_dalek::PublicKey,
}
impl Maker {
@ -59,13 +61,20 @@ impl Maker {
let settlement_time_interval_hours = time::Duration::hours(24);
let seed = Seed::default();
let noise_static_sk = seed.derive_noise_static_secret();
let noise_static_pk = x25519_dalek::PublicKey::from(&noise_static_sk);
let maker = daemon::MakerActorSystem::new(
db,
wallet_addr,
oracle_pk,
|_, _| oracle,
|_, _| async { Ok(monitor) },
|channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1),
|channel0, channel1| {
maker_inc_connections::Actor::new(channel0, channel1, noise_static_sk)
},
settlement_time_interval_hours,
)
.await
@ -95,6 +104,7 @@ impl Maker {
cfd_feed: maker.cfd_feed_receiver,
inc_conn_actor_addr: maker.inc_conn_addr,
listen_addr: address,
noise_static_pk,
mocks,
}
}
@ -126,11 +136,19 @@ pub struct Taker {
}
impl Taker {
pub async fn start(oracle_pk: schnorrsig::PublicKey, maker_address: SocketAddr) -> Self {
pub async fn start(
oracle_pk: schnorrsig::PublicKey,
maker_address: SocketAddr,
maker_noise_pub_key: x25519_dalek::PublicKey,
) -> Self {
let seed = Seed::default();
let noise_static_sk = seed.derive_noise_static_secret();
let connection::Actor {
send_to_maker,
read_from_maker,
} = connection::Actor::new(maker_address)
} = connection::Actor::new(maker_address, maker_noise_pub_key, noise_static_sk)
.await
.expect("Connected to maker");

3
start_all.sh

@ -4,4 +4,5 @@ export RUST_BACKTRACE=1
# A simple command to spin up the complete package, ie. both daemons and frontends.
# A single 'ctrl+c' stops all processes.
(trap 'kill 0' SIGINT; cargo run --bin maker -- testnet & cargo run --bin taker -- testnet & APP=maker yarn --cwd=./frontend dev & APP=taker yarn --cwd=./frontend dev)
# The maker-id is generated from the makers seed found in daemon/util/testnet_seeds/maker_seed
(trap 'kill 0' SIGINT; cargo run --bin maker -- testnet & cargo run --bin taker -- --maker-id 10d4ba2ac3f7a22da4009d813ff1bc3f404dfe2cc93a32bedf1512aa9951c95e testnet -- & APP=maker yarn --cwd=./frontend dev & APP=taker yarn --cwd=./frontend dev)
Loading…
Cancel
Save