Created
September 21, 2019 19:29
-
-
Save cite-reader/6d9b41ef541a69ab2046610f889c5a37 to your computer and use it in GitHub Desktop.
Example code for authenticating CURVE peers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "curve-authenticator" | |
version = "0.1.0" | |
edition = "2018" | |
[dependencies] | |
env_logger = "0.6" | |
log = "0.4" | |
zmq = "0.9.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::ops::Deref; | |
use std::thread; | |
use env_logger::Env; | |
#[allow(unused_imports)] | |
use log::{debug, error, info, trace, warn}; | |
fn main() { | |
env_logger::from_env(Env::default().default_filter_or("info")).init(); | |
let users = vec![ | |
("]7m>Wqh{db/5i0W)-CxjY3lXFKf^EPGd>HNX/0bv", "admin"), | |
(">TJrV[%HOVXw*L=E%}ZIoERs9&Q#juonEcbCyG-{", "karl"), | |
("B)[=t@Ca9P-xnB}}*gW.LNeghD{T)o>omO.@mEMu", "goose"), | |
] | |
.into_iter() | |
.map(|(key, id)| (zmq::z85_decode(key).unwrap(), id.into())) | |
.collect(); | |
let ctx = zmq::Context::new(); | |
let zap = ctx.socket(zmq::ROUTER).unwrap(); | |
zap.set_linger(0).unwrap(); | |
zap.bind("inproc://zeromq.zap.01").unwrap(); | |
thread::spawn(move || authenticator(zap, users)); | |
let server = ctx.socket(zmq::REP).unwrap(); | |
server.set_zap_domain("example").unwrap(); | |
server.set_curve_server(true).unwrap(); | |
server | |
.set_curve_secretkey(b"[L>!FQkkhludw=47V]a!-yizer?otTeQ#HddzZKJ") | |
.unwrap(); | |
server.set_linger(0).unwrap(); | |
server.bind("tcp://127.0.0.1:*").unwrap(); | |
let server_ep = server.get_last_endpoint().unwrap().unwrap(); | |
thread::spawn(move || echo(server)); | |
let client = ctx.socket(zmq::REQ).unwrap(); | |
client | |
.set_curve_secretkey(b"PenRS7K+38d6jMw=zI#x%j%vsdY!Z])+x1.kz8]T") | |
.unwrap(); | |
client | |
.set_curve_publickey(b"]7m>Wqh{db/5i0W)-CxjY3lXFKf^EPGd>HNX/0bv") | |
.unwrap(); | |
client | |
.set_curve_serverkey(b"jQv(P^z%Y3%fh)yMxMvf!yMDJ^HmY.@IaeszH@&l") | |
.unwrap(); | |
client.set_linger(0).unwrap(); | |
client.connect(&server_ep).unwrap(); | |
client.send("PING", 0).unwrap(); | |
client.recv_msg(0).unwrap(); | |
} | |
fn authenticator(s: zmq::Socket, known_keys: HashMap<Vec<u8>, String>) -> zmq::Result<Void> { | |
loop { | |
auth_one(&s, &known_keys)?; | |
} | |
} | |
macro_rules! zap_part { | |
($socket:expr) => {{ | |
let part = $socket.recv_msg(0)?; | |
if !part.get_more() { | |
error!("Buggy ZAP server did not send a complete message"); | |
return Ok(()); | |
} | |
part | |
}}; | |
} | |
fn auth_one(s: &zmq::Socket, known_keys: &HashMap<Vec<u8>, String>) -> zmq::Result<()> { | |
let mut have_envelope = false; | |
let mut envelope = vec![]; | |
while !have_envelope { | |
let part = s.recv_msg(0)?; | |
if !part.get_more() { | |
error!("Buggy ZAP server did not send any message content"); | |
return Ok(()); | |
} | |
if &*part == b"" { | |
have_envelope = true; | |
} | |
envelope.push(part); | |
} | |
debug!("starting a ZAP request"); | |
let version = zap_part!(s); | |
let request_id = zap_part!(s); | |
let _domain = zap_part!(s); | |
let _address = zap_part!(s); | |
let _identity = zap_part!(s); | |
let mechanism = s.recv_msg(0)?; | |
let mut have_all_creds = !mechanism.get_more(); | |
let mut credentials = vec![]; | |
while !have_all_creds { | |
let cred_part = s.recv_msg(0)?; | |
have_all_creds = !cred_part.get_more(); | |
credentials.push(cred_part); | |
} | |
if &*version != b"1.0" { | |
warn!("A ZAP server requested a ZAP version not 1.0"); | |
return zap_response( | |
s, | |
envelope, | |
request_id, | |
500, | |
"ZAP handler doesn't recognize that ZAP version", | |
"", | |
); | |
} | |
if &*mechanism != b"CURVE" || credentials.len() != 1 { | |
error!("This is demo code that only handles simple CURVE auth"); | |
return zap_response( | |
s, | |
envelope, | |
request_id, | |
500, | |
"Don't want to handle that mechanism", | |
"", | |
); | |
} | |
let peer_key = &credentials[0]; | |
if (&*peer_key).len() != 32 { | |
error!("Buggy ZAP server gave us a key of the wrong length"); | |
return zap_response(s, envelope, request_id, 500, "wrong key length", ""); | |
} | |
if let Some(user_id) = known_keys.get(peer_key.deref()) { | |
info!("Authenticated user {:?}", user_id); | |
return zap_response(s, envelope, request_id, 200, "OK", user_id); | |
} else { | |
info!("Unauthorized user"); | |
return zap_response(s, envelope, request_id, 400, "Unknown Key", ""); | |
} | |
} | |
fn zap_response( | |
s: &zmq::Socket, | |
envelope: Vec<zmq::Message>, | |
request_id: zmq::Message, | |
status: i32, | |
status_text: &str, | |
user_id: &str, | |
) -> zmq::Result<()> { | |
for frame in envelope { | |
s.send(frame, zmq::SNDMORE)?; | |
} | |
s.send("1.0", zmq::SNDMORE)?; | |
s.send(request_id, zmq::SNDMORE)?; | |
s.send(&format!("{}", status), zmq::SNDMORE)?; | |
s.send(status_text, zmq::SNDMORE)?; | |
s.send(user_id, zmq::SNDMORE)?; | |
s.send("", 0)?; | |
Ok(()) | |
} | |
fn echo(s: zmq::Socket) -> zmq::Result<Void> { | |
loop { | |
let msg = s.recv_msg(0)?; | |
debug!("message {:?}", &*msg); | |
s.send(msg, 0)?; | |
} | |
} | |
enum Void {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment