X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=multipass.rs;h=8423cd9646939e39beadb590e227889380a37e9a;hb=e34ebce6d26b46e98d3660194608180a48cf3631;hp=d3187aa283b07c407df9373f93878fda8b94f235;hpb=01cde802e8fa5f43ee260fd87973753ef95ce249;p=linux-dallas-multipass diff --git a/multipass.rs b/multipass.rs index d3187aa..8423cd9 100644 --- a/multipass.rs +++ b/multipass.rs @@ -4,13 +4,12 @@ extern crate pcsc; #[macro_use] extern crate simple_error; +#[macro_use] +extern crate serde_json; use pcsc::*; use core::task::{Context, Poll}; -use futures_util::{ - future::TryFutureExt, - stream::{Stream, StreamExt, TryStreamExt}, -}; +use futures_util::stream::{Stream, StreamExt}; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Method, Request, Response, Server, StatusCode}; use hyper::header::HeaderValue; @@ -64,18 +63,25 @@ async fn run_server() -> Result<(), Box> { // Create a TCP listener via tokio. let mut tcp = TcpListener::bind(&addr).await?; - let tls_acceptor = TlsAcceptor::from(tls_cfg); + let tls_acceptor = &TlsAcceptor::from(tls_cfg); // Prepare a long-running future stream to accept and serve cients. let incoming_tls_stream = tcp .incoming() - .map_err(|e| error(format!("Incoming failed: {:?}", e))) - .and_then(move |s| { - tls_acceptor.accept(s).map_err(|e| { - println!("[!] Voluntary server halt due to client-connection error..."); - // Errors could be handled here, instead of server aborting. - // println!("TLS Error: {:?}", e); - error(format!("TLS Error: {:?}", e)) - }) + .filter_map(move |s| async move { + let client = match s { + Ok(x) => x, + Err(e) => { + println!("Failed to accept a client, should probably back off"); + return Some(Err(e)); + } + }; + match tls_acceptor.accept(client).await { + Ok(x) => Some(Ok(x)), + Err(e) => { + println!("[!] Client connection error: {}", e); + None + } + } }) .boxed(); @@ -157,20 +163,21 @@ async fn apdu_service(req: Request) -> Result, hyper::Error *response.status_mut() = StatusCode::BAD_REQUEST; } (&Method::POST, "/scard/version/") => { - *response.body_mut() = Body::from("{\"version\":\"1.3.9.46\"}"); + let reply = json!({ + "version": "1.3.9.46" + }); + *response.body_mut() = Body::from(reply.to_string()); } (&Method::POST, "/scard/list/") => { return unwrap_result_into_response(get_readers(), response); } (&Method::POST, "/scard/disconnect/") => { - *response.body_mut() = Body::from("{\"errorcode\":0,\"errordetail\":0,\"apduresponses\":null}"); + *response.body_mut() = Body::from(""); println!("Disconnecting from card."); let mut card = GLOBAL_CARD.lock().unwrap(); *card = None; } (&Method::POST, "/scard/getref/") => { - let mut reply = "{\"data\":\"".to_owned(); - // This is seemingly so that the PIN isn't sent “in the clear”, over TLS, to localhost. // We send a key (in the form of 16 bytes) with an ID (the reference), // the first four bytes are XORed with the next four bytes, and the PIN @@ -179,10 +186,12 @@ async fn apdu_service(req: Request) -> Result, hyper::Error // be a noop. (The reference is a handle to the key, in case we've given // out multiple ones. We set it to some dummy value.) let random_bytes = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - reply += &hex::encode(random_bytes).to_ascii_uppercase(); - reply += "\",\"ref\":195948557}"; - println!("Reply: {}", reply); - *response.body_mut() = Body::from(reply); + let reply = json!({ + "data": &hex::encode(random_bytes).to_ascii_uppercase(), + "ref": 195948557 + }); + println!("Reply: {}", reply.to_string()); + *response.body_mut() = Body::from(reply.to_string()); } // Catch-all 404. _ => { @@ -224,30 +233,29 @@ fn get_readers() -> Result> // Establish a PC/SC context. let ctx = pcsc::Context::establish(Scope::User)?; - let mut reply : String = "{\"errorcode\":0,\"errordetail\":0,\"readers\":[".to_owned(); - // List available readers. let mut readers_buf = [0; 2048]; - let mut reader_json : Vec = Vec::new(); + let mut reader_json : Vec = Vec::new(); for r in ctx.list_readers(&mut readers_buf)? { // Check the card status by connecting to it. let status = match ctx.connect(r, ShareMode::Shared, Protocols::ANY) { - Ok(_) => "302", - Err(_) => "303" + Ok(_) => 302, + Err(_) => 303 }; - let mut json = "{\"cardstatus\":".to_owned(); - json += status; - json += ",\"name\":\""; - json += r.to_str()?; - json += "\"}"; - reader_json.push(json); + reader_json.push(json!({ + "cardstatus": status, + "name": r.to_str()? + })); } - reply += &reader_json.join(","); - reply += "]}"; - println!("Reply: {}", reply); - return Ok(Body::from(reply)); + let reply = json!({ + "errorcode": 0, + "errordetail": 0, + "readers": reader_json + }); + println!("Reply: {}", reply.to_string()); + return Ok(Body::from(reply.to_string())); } fn transmit_apdu(card: &Card, mut apdu: &[u8]) -> Result> { @@ -344,18 +352,24 @@ fn run_apdu(reader_name: &str, apdus: Vec>) -> Result = Vec::new(); + let mut response_json : Vec = Vec::new(); for apdu in apdus { - let mut reply : String = "{\"apdu\":\"".to_owned(); - reply += &transmit_apdu(card.as_mut().unwrap(), &apdu)?; - reply += "\"}"; - response_json.push(reply); + let reply = match transmit_apdu(card.as_mut().unwrap(), &apdu) { + Ok(r) => r, + Err(err) => { + *card = None; // Clean up. + return Err(err); + } + }; + response_json.push(json!({ + "apdu": reply + })); } - - reply += &response_json.join(","); - reply += "]}"; - println!("Reply: {}", reply); - return Ok(Body::from(reply)); + let reply = json!({ + "errorcode": 0, + "errordetail": 0, + "apduresponses": response_json + }); + println!("Reply: {}", reply.to_string()); + return Ok(Body::from(reply.to_string())); }