From f80c952f6f25b09946a288a51be8016849957553 Mon Sep 17 00:00:00 2001 From: Stuart Stock Date: Sat, 17 Mar 2018 05:28:59 -0500 Subject: Apply default rustfmt style to the project. --- CONTRIBUTING.md | 2 +- benches/messages.rs | 199 ++++++++++++++++++++++++------------------------ src/bin/client.rs | 213 ++++++++++++++++++++++++++++++++++------------------ src/bin/server.rs | 180 ++++++++++++++++++++++++++------------------ src/error.rs | 1 + src/lib.rs | 12 +-- src/merkle.rs | 26 ++++--- src/message.rs | 32 ++++---- src/sign.rs | 40 +++++----- src/tag.rs | 4 +- 10 files changed, 406 insertions(+), 303 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2a8c77..789d778 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ Please open a pull request (PR) for your changes and include: * An overall description/rationale of the PR * Tests for any new functionality -* Code style that matches what is already in the repo +* Code formatted with `rustfmt` default style settings * License (Apache 2.0) and copyright statements for your code * A willingness to iterate and make changes ;) diff --git a/benches/messages.rs b/benches/messages.rs index bf24319..4523859 100644 --- a/benches/messages.rs +++ b/benches/messages.rs @@ -1,141 +1,138 @@ +extern crate byteorder; #[macro_use] extern crate criterion; -extern crate roughenough; extern crate ring; -extern crate byteorder; +extern crate roughenough; extern crate time; use ring::digest; use ring::rand::SecureRandom; use byteorder::{LittleEndian, WriteBytesExt}; -use criterion::{Criterion, black_box}; +use criterion::{black_box, Criterion}; use roughenough::{RtMessage, Tag}; use roughenough::{SIGNED_RESPONSE_CONTEXT, TREE_LEAF_TWEAK}; use roughenough::sign::Signer; fn single_field(data: &[u8]) -> RtMessage { - let mut msg = RtMessage::new(1); - msg.add_field(Tag::NONC, &data[0..63]).unwrap(); - msg + let mut msg = RtMessage::new(1); + msg.add_field(Tag::NONC, &data[0..63]).unwrap(); + msg } fn two_fields(data: &[u8]) -> RtMessage { - let mut msg = RtMessage::new(2); - msg.add_field(Tag::NONC, &data[0..63]).unwrap(); - msg.add_field(Tag::PAD, &data[64..127]).unwrap(); - msg + let mut msg = RtMessage::new(2); + msg.add_field(Tag::NONC, &data[0..63]).unwrap(); + msg.add_field(Tag::PAD, &data[64..127]).unwrap(); + msg } // Full-sized server response fn five_fields(data: &[u8]) -> RtMessage { - let mut response = RtMessage::new(5); - response.add_field(Tag::SIG, &data[0..63]).unwrap(); - response.add_field(Tag::PATH, &data[64..127]).unwrap(); - response.add_field(Tag::SREP, &data[128..191]).unwrap(); - response.add_field(Tag::CERT, &data[192..255]).unwrap(); - response.add_field(Tag::INDX, &data[256..319]).unwrap(); - - response + let mut response = RtMessage::new(5); + response.add_field(Tag::SIG, &data[0..63]).unwrap(); + response.add_field(Tag::PATH, &data[64..127]).unwrap(); + response.add_field(Tag::SREP, &data[128..191]).unwrap(); + response.add_field(Tag::CERT, &data[192..255]).unwrap(); + response.add_field(Tag::INDX, &data[256..319]).unwrap(); + + response } /// Random data for composing a response fn make_data(len: usize) -> Vec { - let rng = ring::rand::SystemRandom::new(); - let mut tmp = vec![1u8; len]; - rng.fill(&mut tmp).unwrap(); + let rng = ring::rand::SystemRandom::new(); + let mut tmp = vec![1u8; len]; + rng.fill(&mut tmp).unwrap(); - tmp + tmp } fn message_creation(c: &mut Criterion) { - let data = make_data(320); - - // TODO(stuart) .to_vec()'s below because I'm fighting the borrow-checker. - // Tried iter_with_setup(), but haven't found the right combo of 'move' - // and reference lifetime(s) yet. - - let d1 = data.to_vec(); - c.bench_function("single field", - move |b| b.iter(|| black_box(single_field(&d1))), - ); - - let d2 = data.to_vec(); - c.bench_function("two fields", - move |b| b.iter(|| black_box(two_fields(&d2))), - ); - - let d3 = data.to_vec(); - c.bench_function("five fields", - move |b| b.iter(|| black_box(five_fields(&d3))), - ); + let data = make_data(320); + + // TODO(stuart) .to_vec()'s below because I'm fighting the borrow-checker. + // Tried iter_with_setup(), but haven't found the right combo of 'move' + // and reference lifetime(s) yet. + + let d1 = data.to_vec(); + c.bench_function("single field", move |b| { + b.iter(|| black_box(single_field(&d1))) + }); + + let d2 = data.to_vec(); + c.bench_function("two fields", move |b| b.iter(|| black_box(two_fields(&d2)))); + + let d3 = data.to_vec(); + c.bench_function("five fields", move |b| { + b.iter(|| black_box(five_fields(&d3))) + }); } /// TODO(stuart) straight-up copied form src/bin/server.rs, not ideal at all fn make_response(ephemeral_key: &mut Signer, cert_bytes: &[u8], nonce: &[u8]) -> RtMessage { - let path = [0u8; 0]; - let zeros = [0u8; 4]; - - let mut radi: Vec = Vec::with_capacity(4); - let mut midp: Vec = Vec::with_capacity(8); - - // one second (in microseconds) - radi.write_u32::(1_000_000).unwrap(); - - // current epoch time in microseconds - let now = { - let tv = time::get_time(); - let secs = (tv.sec as u64) * 1_000_000; - let nsecs = (tv.nsec as u64) / 1_000; - - secs + nsecs - }; - midp.write_u64::(now).unwrap(); - - // Signed response SREP - let srep_bytes = { - // hash request nonce - let mut ctx = digest::Context::new(&digest::SHA512); - ctx.update(TREE_LEAF_TWEAK); - ctx.update(nonce); - let digest = ctx.finish(); - - let mut srep_msg = RtMessage::new(3); - srep_msg.add_field(Tag::RADI, &radi).unwrap(); - srep_msg.add_field(Tag::MIDP, &midp).unwrap(); - srep_msg.add_field(Tag::ROOT, digest.as_ref()).unwrap(); - - srep_msg.encode().unwrap() - }; - - // signature on SREP - let srep_signature = { - ephemeral_key.update(SIGNED_RESPONSE_CONTEXT.as_bytes()); - ephemeral_key.update(&srep_bytes); - ephemeral_key.sign() - }; - - let mut response = RtMessage::new(5); - response.add_field(Tag::SIG, &srep_signature).unwrap(); - response.add_field(Tag::PATH, &path).unwrap(); - response.add_field(Tag::SREP, &srep_bytes).unwrap(); - response.add_field(Tag::CERT, cert_bytes).unwrap(); - response.add_field(Tag::INDX, &zeros).unwrap(); - - response + let path = [0u8; 0]; + let zeros = [0u8; 4]; + + let mut radi: Vec = Vec::with_capacity(4); + let mut midp: Vec = Vec::with_capacity(8); + + // one second (in microseconds) + radi.write_u32::(1_000_000).unwrap(); + + // current epoch time in microseconds + let now = { + let tv = time::get_time(); + let secs = (tv.sec as u64) * 1_000_000; + let nsecs = (tv.nsec as u64) / 1_000; + + secs + nsecs + }; + midp.write_u64::(now).unwrap(); + + // Signed response SREP + let srep_bytes = { + // hash request nonce + let mut ctx = digest::Context::new(&digest::SHA512); + ctx.update(TREE_LEAF_TWEAK); + ctx.update(nonce); + let digest = ctx.finish(); + + let mut srep_msg = RtMessage::new(3); + srep_msg.add_field(Tag::RADI, &radi).unwrap(); + srep_msg.add_field(Tag::MIDP, &midp).unwrap(); + srep_msg.add_field(Tag::ROOT, digest.as_ref()).unwrap(); + + srep_msg.encode().unwrap() + }; + + // signature on SREP + let srep_signature = { + ephemeral_key.update(SIGNED_RESPONSE_CONTEXT.as_bytes()); + ephemeral_key.update(&srep_bytes); + ephemeral_key.sign() + }; + + let mut response = RtMessage::new(5); + response.add_field(Tag::SIG, &srep_signature).unwrap(); + response.add_field(Tag::PATH, &path).unwrap(); + response.add_field(Tag::SREP, &srep_bytes).unwrap(); + response.add_field(Tag::CERT, cert_bytes).unwrap(); + response.add_field(Tag::INDX, &zeros).unwrap(); + + response } fn response_creation(c: &mut Criterion) { - let nonce = make_data(64); - let cert = make_data(152); - let seed = make_data(32); - let mut signer = Signer::new(&seed); - - c.bench_function("server response", - move |b| b.iter(|| black_box(make_response(&mut signer, &cert, &nonce))), - ); + let nonce = make_data(64); + let cert = make_data(152); + let seed = make_data(32); + let mut signer = Signer::new(&seed); + + c.bench_function("server response", move |b| { + b.iter(|| black_box(make_response(&mut signer, &cert, &nonce))) + }); } criterion_group!(benches, message_creation, response_creation); criterion_main!(benches); - diff --git a/src/bin/client.rs b/src/bin/client.rs index d9b37fc..d24315b 100644 --- a/src/bin/client.rs +++ b/src/bin/client.rs @@ -1,11 +1,23 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate byteorder; +extern crate chrono; #[macro_use] extern crate clap; -extern crate roughenough; +extern crate hex; extern crate ring; +extern crate roughenough; extern crate time; -extern crate chrono; -extern crate byteorder; -extern crate hex; use ring::rand; use ring::rand::SecureRandom; @@ -17,12 +29,12 @@ use chrono::offset::Utc; use std::iter::Iterator; use std::collections::HashMap; -use std::net::{UdpSocket, ToSocketAddrs}; +use std::net::{ToSocketAddrs, UdpSocket}; -use roughenough::{RtMessage, Tag, VERSION, CERTIFICATE_CONTEXT, SIGNED_RESPONSE_CONTEXT}; +use roughenough::{RtMessage, Tag, CERTIFICATE_CONTEXT, SIGNED_RESPONSE_CONTEXT, VERSION}; use roughenough::sign::Verifier; use roughenough::merkle::root_from_paths; -use clap::{Arg, App}; +use clap::{App, Arg}; fn create_nonce() -> [u8; 64] { let rng = rand::SystemRandom::new(); @@ -43,32 +55,37 @@ fn make_request(nonce: &[u8]) -> Vec { fn receive_response(sock: &mut UdpSocket) -> RtMessage { let mut buf = [0; 744]; let resp_len = sock.recv_from(&mut buf).unwrap().0; + RtMessage::from_bytes(&buf[0..resp_len]).unwrap() } - struct ResponseHandler { pub_key: Option>, msg: HashMap>, srep: HashMap>, cert: HashMap>, dele: HashMap>, - nonce: [u8; 64] + nonce: [u8; 64], } struct ParsedResponse { verified: bool, midpoint: u64, - radius: u32 + radius: u32, } impl ResponseHandler { pub fn new(pub_key: Option>, response: RtMessage, nonce: [u8; 64]) -> ResponseHandler { let msg = response.into_hash_map(); - let srep = RtMessage::from_bytes(&msg[&Tag::SREP]).unwrap().into_hash_map(); - let cert = RtMessage::from_bytes(&msg[&Tag::CERT]).unwrap().into_hash_map(); - - let dele = RtMessage::from_bytes(&cert[&Tag::DELE]).unwrap().into_hash_map(); + let srep = RtMessage::from_bytes(&msg[&Tag::SREP]) + .unwrap() + .into_hash_map(); + let cert = RtMessage::from_bytes(&msg[&Tag::CERT]) + .unwrap() + .into_hash_map(); + let dele = RtMessage::from_bytes(&cert[&Tag::DELE]) + .unwrap() + .into_hash_map(); ResponseHandler { pub_key, @@ -76,13 +93,19 @@ impl ResponseHandler { srep, cert, dele, - nonce + nonce, } } pub fn extract_time(&self) -> ParsedResponse { - let midpoint = self.srep[&Tag::MIDP].as_slice().read_u64::().unwrap(); - let radius = self.srep[&Tag::RADI].as_slice().read_u32::().unwrap(); + let midpoint = self.srep[&Tag::MIDP] + .as_slice() + .read_u64::() + .unwrap(); + let radius = self.srep[&Tag::RADI] + .as_slice() + .read_u32::() + .unwrap(); let mut verified = false; if self.pub_key.is_some() { @@ -96,7 +119,7 @@ impl ResponseHandler { ParsedResponse { verified, midpoint, - radius + radius, } } @@ -104,35 +127,63 @@ impl ResponseHandler { let mut full_cert = Vec::from(CERTIFICATE_CONTEXT.as_bytes()); full_cert.extend(&self.cert[&Tag::DELE]); - assert!(self.validate_sig(self.pub_key.as_ref().unwrap(), &self.cert[&Tag::SIG], &full_cert), - "Invalid signature on DELE tag!"); + assert!( + self.validate_sig( + self.pub_key.as_ref().unwrap(), + &self.cert[&Tag::SIG], + &full_cert + ), + "Invalid signature on DELE tag!" + ); } fn validate_srep(&self) { let mut full_srep = Vec::from(SIGNED_RESPONSE_CONTEXT.as_bytes()); full_srep.extend(&self.msg[&Tag::SREP]); - assert!(self.validate_sig(&self.dele[&Tag::PUBK], &self.msg[&Tag::SIG], &full_srep), - "Invalid signature on SREP tag!"); + assert!( + self.validate_sig(&self.dele[&Tag::PUBK], &self.msg[&Tag::SIG], &full_srep), + "Invalid signature on SREP tag!" + ); } fn validate_merkle(&self) { - let srep = RtMessage::from_bytes(&self.msg[&Tag::SREP]).unwrap().into_hash_map(); - let index = self.msg[&Tag::INDX].as_slice().read_u32::().unwrap(); + let srep = RtMessage::from_bytes(&self.msg[&Tag::SREP]) + .unwrap() + .into_hash_map(); + let index = self.msg[&Tag::INDX] + .as_slice() + .read_u32::() + .unwrap(); let paths = &self.msg[&Tag::PATH]; - let hash = root_from_paths(index as usize, &self.nonce, paths); - - assert_eq!(Vec::from(hash), srep[&Tag::ROOT], "Nonce not in merkle tree!"); + let hash = root_from_paths(index as usize, &self.nonce, paths); + assert_eq!( + Vec::from(hash), + srep[&Tag::ROOT], + "Nonce not in merkle tree!" + ); } fn validate_midpoint(&self, midpoint: u64) { - let mint = self.dele[&Tag::MINT].as_slice().read_u64::().unwrap(); - let maxt = self.dele[&Tag::MAXT].as_slice().read_u64::().unwrap(); - - assert!(midpoint >= mint, "Response midpoint {} lies before delegation span ({}, {})"); - assert!(midpoint <= maxt, "Response midpoint {} lies after delegation span ({}, {})"); + let mint = self.dele[&Tag::MINT] + .as_slice() + .read_u64::() + .unwrap(); + let maxt = self.dele[&Tag::MAXT] + .as_slice() + .read_u64::() + .unwrap(); + + assert!( + midpoint >= mint, + "Response midpoint {} lies before delegation span ({}, {})" + ); + assert!( + midpoint <= maxt, + "Response midpoint {} lies after delegation span ({}, {})" + ); } fn validate_sig(&self, public_key: &[u8], sig: &[u8], data: &[u8]) -> bool { @@ -144,56 +195,60 @@ impl ResponseHandler { fn main() { let matches = App::new("roughenough client") - .version(VERSION) - .arg(Arg::with_name("host") - .required(true) - .help("The Roughtime server to connect to") - .takes_value(true)) - .arg(Arg::with_name("port") - .required(true) - .help("The Roughtime server port to connect to") - .takes_value(true)) - .arg(Arg::with_name("public-key") - .short("p") - .long("public-key") - .takes_value(true) - .help("The server public key used to validate responses. If unset, no validation will be performed")) - .arg(Arg::with_name("time-format") - .short("f") - .long("time-format") - .takes_value(true) - .help("The strftime format string used to print the time recieved from the server") - .default_value("%b %d %Y %H:%M:%S") - ) - .arg(Arg::with_name("num-requests") - .short("n") - .long("num-requests") - .takes_value(true) - .help("The number of requests to make to the server (each from a different source port). This is mainly useful for testing batch response handling") - .default_value("1") - ) - .arg(Arg::with_name("stress") - .short("s") - .long("stress") - .help("Stress-tests the server by sending the same request as fast as possible. Please only use this on your own server") - ) - .get_matches(); + .version(VERSION) + .arg(Arg::with_name("host") + .required(true) + .help("The Roughtime server to connect to") + .takes_value(true)) + .arg(Arg::with_name("port") + .required(true) + .help("The Roughtime server port to connect to") + .takes_value(true)) + .arg(Arg::with_name("public-key") + .short("p") + .long("public-key") + .takes_value(true) + .help("The server public key used to validate responses. If unset, no validation will be performed")) + .arg(Arg::with_name("time-format") + .short("f") + .long("time-format") + .takes_value(true) + .help("The strftime format string used to print the time recieved from the server") + .default_value("%b %d %Y %H:%M:%S") + ) + .arg(Arg::with_name("num-requests") + .short("n") + .long("num-requests") + .takes_value(true) + .help("The number of requests to make to the server (each from a different source port). This is mainly useful for testing batch response handling") + .default_value("1") + ) + .arg(Arg::with_name("stress") + .short("s") + .long("stress") + .help("Stress-tests the server by sending the same request as fast as possible. Please only use this on your own server") + ) + .get_matches(); let host = matches.value_of("host").unwrap(); let port = value_t_or_exit!(matches.value_of("port"), u16); let num_requests = value_t_or_exit!(matches.value_of("num-requests"), u16) as usize; - let pub_key = matches.value_of("public-key").map(|pkey| hex::decode(pkey).expect("Error parsing public key!")); let time_format = matches.value_of("time-format").unwrap(); let stress = matches.is_present("stress"); + let pub_key = matches + .value_of("public-key") + .map(|pkey| hex::decode(pkey).expect("Error parsing public key!")); println!("Requesting time from: {:?}:{:?}", host, port); let addr = (host, port).to_socket_addrs().unwrap().next().unwrap(); if stress { - if !addr.ip().is_loopback() { - println!("ERROR: Cannot use non-loopback address {} for stress testing", addr.ip()); + println!( + "ERROR: Cannot use non-loopback address {} for stress testing", + addr.ip() + ); return; } @@ -208,7 +263,6 @@ fn main() { } } - let mut requests = Vec::with_capacity(num_requests); for _ in 0..num_requests { @@ -226,15 +280,26 @@ fn main() { for (nonce, _, mut socket) in requests { let resp = receive_response(&mut socket); - let ParsedResponse {verified, midpoint, radius} = ResponseHandler::new(pub_key.clone(), resp.clone(), nonce).extract_time(); + let ParsedResponse { + verified, + midpoint, + radius, + } = ResponseHandler::new(pub_key.clone(), resp.clone(), nonce).extract_time(); let map = resp.into_hash_map(); - let index = map[&Tag::INDX].as_slice().read_u32::().unwrap(); + let index = map[&Tag::INDX] + .as_slice() + .read_u32::() + .unwrap(); let seconds = midpoint / 10_u64.pow(6); - let spec = Utc.timestamp(seconds as i64, ((midpoint - (seconds * 10_u64.pow(6))) * 10_u64.pow(3)) as u32); + let nsecs = (midpoint - (seconds * 10_u64.pow(6))) * 10_u64.pow(3); + let spec = Utc.timestamp(seconds as i64, nsecs as u32); let out = spec.format(time_format).to_string(); - println!("Recieved time from server: midpoint={:?}, radius={:?} (merkle_index={}, verified={})", out, radius, index, verified); + println!( + "Received time from server: midpoint={:?}, radius={:?} (merkle_index={}, verified={})", + out, radius, index, verified + ); } } diff --git a/src/bin/server.rs b/src/bin/server.rs index c38066a..18ebdaf 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -29,7 +29,7 @@ //! //! * **interface** - IP address or interface name for listening to client requests //! * **port** - UDP port to listen to requests -//! * **seed** - A 32-byte hexadecimal value used as the seed to generate the +//! * **seed** - A 32-byte hexadecimal value used as the seed to generate the //! server's long-term key pair. **This is a secret value**, treat it //! with care. //! * **batch_size** - The number of requests to process in one batch. All nonces @@ -43,37 +43,37 @@ //! ``` extern crate byteorder; -extern crate ring; -extern crate roughenough; -extern crate time; -extern crate untrusted; extern crate ctrlc; -extern crate yaml_rust; +extern crate hex; #[macro_use] extern crate log; -extern crate simple_logger; extern crate mio; extern crate mio_extras; -extern crate hex; +extern crate ring; +extern crate roughenough; +extern crate simple_logger; +extern crate time; +extern crate untrusted; +extern crate yaml_rust; use std::env; use std::process; use std::fs::File; -use std::io::{Read, ErrorKind}; +use std::io::{ErrorKind, Read}; use std::time::Duration; use std::net::SocketAddr; use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::thread; -use mio::{Poll, Token, Ready, PollOpt, Events}; +use mio::{Events, Poll, PollOpt, Ready, Token}; use mio::net::UdpSocket; use mio_extras::timer::Timer; use byteorder::{LittleEndian, WriteBytesExt}; -use roughenough::{RtMessage, Tag, Error}; -use roughenough::{VERSION, CERTIFICATE_CONTEXT, MIN_REQUEST_LENGTH, SIGNED_RESPONSE_CONTEXT}; +use roughenough::{Error, RtMessage, Tag}; +use roughenough::{CERTIFICATE_CONTEXT, MIN_REQUEST_LENGTH, SIGNED_RESPONSE_CONTEXT, VERSION}; use roughenough::sign::Signer; use roughenough::merkle::*; @@ -109,8 +109,14 @@ fn make_key_and_cert(seed: &[u8]) -> (Signer, Vec) { let mut long_term_key = Signer::new(seed); let ephemeral_key = create_ephemeral_key(); - info!("Long-term public key: {}", hex::encode(long_term_key.public_key_bytes())); - info!("Ephemeral public key: {}", hex::encode(ephemeral_key.public_key_bytes())); + info!( + "Long-term public key: {}", + hex::encode(long_term_key.public_key_bytes()) + ); + info!( + "Ephemeral public key: {}", + hex::encode(ephemeral_key.public_key_bytes()) + ); // Make DELE and sign it with long-term key let dele_bytes = make_dele_bytes(&ephemeral_key).unwrap(); @@ -134,26 +140,17 @@ fn make_key_and_cert(seed: &[u8]) -> (Signer, Vec) { struct SRep { raw_bytes: Vec, - signature: Vec + signature: Vec, } fn make_srep(ephemeral_key: &mut Signer, root: &[u8]) -> SRep { - // create SREP - // sign SREP - // create response: - // - SIG - // - PATH (always 0) - // - SREP - // - CERT (pre-created) - // - INDX (always 0) - - let mut radi = [0; 4]; let mut midp = [0; 8]; - // one second (in microseconds) - (&mut radi as &mut [u8]).write_u32::(1_000_000).unwrap(); + (&mut radi as &mut [u8]) + .write_u32::(1_000_000) + .unwrap(); // current epoch time in microseconds let now = { @@ -163,7 +160,9 @@ fn make_srep(ephemeral_key: &mut Signer, root: &[u8]) -> SRep { secs + nsecs }; - (&mut midp as &mut [u8]).write_u64::(now).unwrap(); + (&mut midp as &mut [u8]) + .write_u64::(now) + .unwrap(); // Signed response SREP let srep_bytes = { @@ -184,15 +183,15 @@ fn make_srep(ephemeral_key: &mut Signer, root: &[u8]) -> SRep { SRep { raw_bytes: srep_bytes, - signature: srep_signature + signature: srep_signature, } } fn make_response(srep: &SRep, cert_bytes: &[u8], path: &[u8], idx: u32) -> RtMessage { - let mut index = [0; 4]; - (&mut index as &mut [u8]).write_u32::(idx).unwrap(); - + (&mut index as &mut [u8]) + .write_u32::(idx) + .unwrap(); let mut response = RtMessage::new(5); response.add_field(Tag::SIG, &srep.signature).unwrap(); @@ -226,15 +225,14 @@ fn nonce_from_request(buf: &[u8], num_bytes: usize) -> Result<&[u8], Error> { } fn load_config(config_file: &str) -> (SocketAddr, Vec, u8) { - let mut infile = File::open(config_file) - .expect("failed to open config file"); + let mut infile = File::open(config_file).expect("failed to open config file"); let mut contents = String::new(); - infile.read_to_string(&mut contents) + infile + .read_to_string(&mut contents) .expect("could not read config file"); - let cfg = YamlLoader::load_from_str(&contents) - .expect("could not parse config file"); + let cfg = YamlLoader::load_from_str(&contents).expect("could not parse config file"); if cfg.len() != 1 { panic!("empty or malformed config file"); @@ -251,7 +249,7 @@ fn load_config(config_file: &str) -> (SocketAddr, Vec, u8) { "interface" => iface = value.as_str().unwrap().to_string(), "seed" => seed = value.as_str().unwrap().to_string(), "batch_size" => batch_size = value.as_i64().unwrap() as u8, - _ => warn!("ignoring unknown config key '{}'", key.as_str().unwrap()) + _ => warn!("ignoring unknown config key '{}'", key.as_str().unwrap()), } } @@ -259,13 +257,19 @@ fn load_config(config_file: &str) -> (SocketAddr, Vec, u8) { let sock_addr: SocketAddr = addr.parse() .expect(&format!("could not create socket address from {}", addr)); - let binseed = hex::decode(seed) - .expect("seed value invalid; 'seed' should be 32 byte hex value"); + let binseed = + hex::decode(seed).expect("seed value invalid; 'seed' should be 32 byte hex value"); (sock_addr, binseed, batch_size) } -fn polling_loop(addr: &SocketAddr, mut ephemeral_key: &mut Signer, cert_bytes: &[u8], batch_size: u8, response_counter: Arc) { +fn polling_loop( + addr: &SocketAddr, + mut ephemeral_key: &mut Signer, + cert_bytes: &[u8], + batch_size: u8, + response_counter: Arc, +) { let keep_running = Arc::new(AtomicBool::new(true)); let kr = keep_running.clone(); @@ -279,26 +283,27 @@ fn polling_loop(addr: &SocketAddr, mut ephemeral_key: &mut Signer, cert_bytes: & let mut timer: Timer<()> = Timer::default(); timer.set_timeout(status_duration, ()); - let mut buf = [0u8; 65_536]; let mut events = Events::with_capacity(32); let mut num_bad_requests = 0u64; let poll = Poll::new().unwrap(); - poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge()).unwrap(); - poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge()).unwrap(); + poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge()) + .unwrap(); + poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge()) + .unwrap(); let mut merkle = MerkleTree::new(); let mut requests = Vec::with_capacity(batch_size as usize); macro_rules! check_ctrlc { - () => { - if !keep_running.load(Ordering::Acquire) { - warn!("Ctrl-C caught, exiting..."); - return; - } + () => { + if !keep_running.load(Ordering::Acquire) { + warn!("Ctrl-C caught, exiting..."); + return; } } + } loop { check_ctrlc!(); @@ -306,10 +311,8 @@ fn polling_loop(addr: &SocketAddr, mut ephemeral_key: &mut Signer, cert_bytes: & poll.poll(&mut events, poll_duration).expect("poll failed"); for event in events.iter() { - match event.token() { MESSAGE => { - let mut done = false; 'process_batch: loop { @@ -328,24 +331,31 @@ fn polling_loop(addr: &SocketAddr, mut ephemeral_key: &mut Signer, cert_bytes: & merkle.push_leaf(nonce); } else { num_bad_requests += 1; - info!("Invalid request ({} bytes) from {} (#{} in batch, resp #{})", num_bytes, src_addr, i, resp_start + i as usize); + info!( + "Invalid request ({} bytes) from {} (#{} in batch, resp #{})", + num_bytes, src_addr, i, resp_start + i as usize + ); } - }, + } Err(e) => match e.kind() { ErrorKind::WouldBlock => { done = true; break; - }, + } _ => { - error!("Error receiving from socket: {:?}: {:?}", e.kind(), e); - break + error!( + "Error receiving from socket: {:?}: {:?}", + e.kind(), + e + ); + break; } - } + }, }; } if requests.is_empty() { - break 'process_batch + break 'process_batch; } let root = merkle.compute_root(); @@ -357,24 +367,37 @@ fn polling_loop(addr: &SocketAddr, mut ephemeral_key: &mut Signer, cert_bytes: & let resp = make_response(&srep, cert_bytes, &paths, i as u32); let resp_bytes = resp.encode().unwrap(); - let bytes_sent = socket.send_to(&resp_bytes, &src_addr).expect("send_to failed"); + let bytes_sent = socket + .send_to(&resp_bytes, &src_addr) + .expect("send_to failed"); let num_responses = response_counter.fetch_add(1, Ordering::SeqCst); - info!("Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})", bytes_sent, src_addr, hex::encode(&nonce[0..4]), i, num_responses); + info!( + "Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})", + bytes_sent, + src_addr, + hex::encode(&nonce[0..4]), + i, + num_responses + ); } if done { - break 'process_batch + break 'process_batch; } } - } STATUS => { - info!("responses {}, invalid requests {}", response_counter.load(Ordering::SeqCst), num_bad_requests); + info!( + "responses {}, invalid requests {}", + response_counter.load(Ordering::SeqCst), + num_bad_requests + ); + timer.set_timeout(status_duration, ()); } - _ => unreachable!() + _ => unreachable!(), } } } @@ -400,26 +423,33 @@ pub fn main() { let response_counter = Arc::new(AtomicUsize::new(0)); - if env::var("BENCH").is_ok() { + if env::var("BENCH").is_ok() { log::set_max_level(log::LevelFilter::Warn); let response_counter = response_counter.clone(); - thread::spawn(move || { - loop { - let old = time::get_time().sec; - let old_reqs = response_counter.load(Ordering::SeqCst); + thread::spawn(move || loop { + let old = time::get_time().sec; + let old_reqs = response_counter.load(Ordering::SeqCst); - thread::sleep(Duration::from_secs(1)); + thread::sleep(Duration::from_secs(1)); - let new = time::get_time().sec; - let new_reqs = response_counter.load(Ordering::SeqCst); + let new = time::get_time().sec; + let new_reqs = response_counter.load(Ordering::SeqCst); - warn!("Processing at {:?} reqs/sec", (new_reqs - old_reqs) / (new - old) as usize); - } + warn!( + "Processing at {:?} reqs/sec", + (new_reqs - old_reqs) / (new - old) as usize + ); }); } - polling_loop(&addr, &mut ephemeral_key, &cert_bytes, batch_size, response_counter.clone()); + polling_loop( + &addr, + &mut ephemeral_key, + &cert_bytes, + batch_size, + response_counter.clone(), + ); info!("Done."); process::exit(0); diff --git a/src/error.rs b/src/error.rs index decc0bc..98f337e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -22,6 +22,7 @@ pub enum Error { /// The associated tag was added to an `RtMessage` in non-increasing order. TagNotStrictlyIncreasing(Tag), + /// The associated byte sequence does not correspond to a valid Roughtime tag. InvalidTag(Box<[u8]>), /// Encoding failed. The associated `std::io::Error` should provide more information. diff --git a/src/lib.rs b/src/lib.rs index 1c3650f..4814398 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,13 +16,13 @@ //! An implementation of the [Roughtime](https://roughtime.googlesource.com/roughtime) //! secure time synchronization protocol. //! -//! Roughtime aims to achieve rough time synchronisation in a secure way that doesn't -//! depend on any particular time server, and in such a way that, if a time server does -//! misbehave, clients end up with cryptographic proof of it. +//! Roughtime aims to achieve rough time synchronisation in a secure way that doesn't +//! depend on any particular time server, and in such a way that, if a time server does +//! misbehave, clients end up with cryptographic proof of it. //! //! # Protocol //! -//! Roughtime messages are represetned by [`RtMessage`](struct.RtMessage.html) which +//! Roughtime messages are represetned by [`RtMessage`](struct.RtMessage.html) which //! implements the mapping of Roughtime `u32` [`tags`](enum.Tag.html) to byte-strings. //! //! # Client @@ -37,7 +37,7 @@ //! //! # Server //! -//! A Roughtime server implementation is in `src/bin/server.rs`. The server is +//! A Roughtime server implementation is in `src/bin/server.rs`. The server is //! configured via a yaml file: //! //! ```yaml @@ -51,7 +51,7 @@ //! //! * **interface** - IP address or interface name for listening to client requests //! * **port** - UDP port to listen to requests -//! * **seed** - A 32-byte hexadecimal value used as the seed to generate the +//! * **seed** - A 32-byte hexadecimal value used as the seed to generate the //! server's long-term key pair. **This is a secret value**, treat it //! with care. //! * **batch_size** - The number of requests to process in one batch. All nonces diff --git a/src/merkle.rs b/src/merkle.rs index 4bb4abd..d55280f 100644 --- a/src/merkle.rs +++ b/src/merkle.rs @@ -14,7 +14,7 @@ extern crate ring; -use super::{TREE_LEAF_TWEAK, TREE_NODE_TWEAK, HASH_LENGTH}; +use super::{HASH_LENGTH, TREE_LEAF_TWEAK, TREE_NODE_TWEAK}; use self::ring::digest; type Data = Vec; @@ -27,7 +27,7 @@ pub struct MerkleTree { impl MerkleTree { pub fn new() -> MerkleTree { MerkleTree { - levels: vec![vec![]] + levels: vec![vec![]], } } @@ -41,11 +41,7 @@ impl MerkleTree { let mut level = 0; while !self.levels[level].is_empty() { - let sibling = if index % 2 == 0 { - index + 1 - } else { - index - 1 - }; + let sibling = if index % 2 == 0 { index + 1 } else { index - 1 }; paths.extend(self.levels[level][sibling].clone()); level += 1; @@ -55,10 +51,14 @@ impl MerkleTree { } pub fn compute_root(&mut self) -> Hash { - assert!(self.levels[0].len() > 0, "Must have at least one leaf to hash!"); + assert!( + self.levels[0].len() > 0, + "Must have at least one leaf to hash!" + ); let mut level = 0; let mut node_count = self.levels[0].len(); + while node_count > 1 { level += 1; @@ -74,10 +74,14 @@ impl MerkleTree { node_count /= 2; for i in 0..node_count { - let hash = self.hash_nodes(&self.levels[level - 1][i*2], &self.levels[level - 1][(i*2)+1]); + let hash = self.hash_nodes( + &self.levels[level - 1][i * 2], + &self.levels[level - 1][(i * 2) + 1], + ); self.levels[level].push(hash); } } + assert_eq!(self.levels[level].len(), 1); self.levels[level].pop().unwrap() } @@ -128,16 +132,16 @@ pub fn root_from_paths(mut index: usize, data: &[u8], paths: &[u8]) -> Hash { ctx.update(path); ctx.update(&hash); } - hash = Hash::from(ctx.finish().as_ref()); + hash = Hash::from(ctx.finish().as_ref()); index >>= 1; } + hash } #[cfg(test)] mod test { - use merkle::*; fn test_paths_with_num(num: usize) { diff --git a/src/message.rs b/src/message.rs index 8a2e1b6..11cad2b 100644 --- a/src/message.rs +++ b/src/message.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::io::{Read, Write, Cursor}; +use std::io::{Cursor, Read, Write}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use std::iter::once; use std::collections::HashMap; @@ -51,28 +51,27 @@ impl RtMessage { if num_tags == 1 { let pos = msg.position() as usize; - let tag = Tag::from_wire(&bytes[pos..pos+4])?; + let tag = Tag::from_wire(&bytes[pos..pos + 4])?; msg.set_position((pos + 4) as u64); let mut value = Vec::new(); - + msg.read_to_end(&mut value).unwrap(); rt_msg.add_field(tag, &value)?; - return Ok(rt_msg) + return Ok(rt_msg); } let mut offsets = Vec::with_capacity((num_tags - 1) as usize); let mut tags = Vec::with_capacity(num_tags as usize); for _ in 0..num_tags - 1 { - let offset = msg.read_u32::()?; + let offset = msg.read_u32::()?; if offset % 4 != 0 { panic!("Invalid offset {:?} in message {:?}", offset, bytes); } offsets.push(offset as usize); } - let mut buf = [0; 4]; for _ in 0..num_tags { msg.read_exact(&mut buf).unwrap(); @@ -80,7 +79,7 @@ impl RtMessage { if let Some(last_tag) = tags.last() { if tag <= *last_tag { - return Err(Error::TagNotStrictlyIncreasing(tag)) + return Err(Error::TagNotStrictlyIncreasing(tag)); } } tags.push(tag); @@ -96,11 +95,10 @@ impl RtMessage { assert_eq!(offsets.len(), tags.len() - 1); for (tag, (value_start, value_end)) in tags.into_iter().zip( - once(&0).chain(offsets.iter()).zip( - offsets.iter().chain(once(&msg_end)) - ) + once(&0) + .chain(offsets.iter()) + .zip(offsets.iter().chain(once(&msg_end))), ) { - let value = bytes[(header_end + value_start)..(header_end + value_end)].to_vec(); rt_msg.add_field(tag, &value)?; } @@ -111,8 +109,8 @@ impl RtMessage { /// /// ## Arguments /// - /// * `tag` - The [`Tag`](enum.Tag.html) to add. Tags must be added in **strictly - /// increasing order**, violating this will result in a + /// * `tag` - The [`Tag`](enum.Tag.html) to add. Tags must be added in **strictly + /// increasing order**, violating this will result in a /// [`Error::TagNotStrictlyIncreasing`](enum.Error.html). /// /// * `value` - Value for the tag. @@ -193,7 +191,7 @@ impl RtMessage { /// Adds a PAD tag to the end of this message, with a length /// set such that the final encoded size of this message is 1KB - /// + /// /// If the encoded size of this message is already >= 1KB, /// this method does nothing pub fn pad_to_kilobyte(&mut self) { @@ -313,8 +311,10 @@ mod test { assert_eq!(encoded.read_u32::().unwrap(), 2); // Offset past DELE value to start of MAXT value - assert_eq!(encoded.read_u32::().unwrap(), - dele_value.len() as u32); + assert_eq!( + encoded.read_u32::().unwrap(), + dele_value.len() as u32 + ); // DELE tag let mut dele = [0u8; 4]; diff --git a/src/sign.rs b/src/sign.rs index d7ef156..a990a2f 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -15,19 +15,19 @@ //! Ed25519 signing and verification //! //! `Ring` does not provide a multi-step (init-update-finish) interface -//! for Ed25519 signatures. `Verifier` and `Signer` provide this +//! for Ed25519 signatures. `Verifier` and `Signer` provide this //! missing multi-step api. +extern crate hex; extern crate ring; extern crate untrusted; -extern crate hex; use self::ring::signature; use self::ring::signature::Ed25519KeyPair; use self::untrusted::Input; -/// A multi-step (init-update-finish) interface for verifying an +/// A multi-step (init-update-finish) interface for verifying an /// Ed25519 signature #[derive(Debug)] pub struct Verifier<'a> { @@ -59,7 +59,7 @@ impl<'a> Verifier<'a> { } } -/// A multi-step (init-update-finish) interface for creating an +/// A multi-step (init-update-finish) interface for creating an /// Ed25519 signature pub struct Signer { key_pair: Ed25519KeyPair, @@ -91,17 +91,20 @@ impl Signer { } } +#[cfg_attr(rustfmt, rustfmt_skip)] // rustfmt errors on the long signature strings #[cfg(test)] mod test { use super::*; #[test] fn verify_ed25519_sig_on_empty_message() { - let pubkey = hex::decode("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a") - .unwrap(); + let pubkey = hex::decode( + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", + ).unwrap(); - let signature = hex::decode("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b") - .unwrap(); + let signature = hex::decode( + "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b" + ).unwrap(); let v = Verifier::new(&pubkey); let result = v.verify(&signature); @@ -110,13 +113,15 @@ mod test { #[test] fn verify_ed25519_sig() { - let pubkey = hex::decode("c0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7") - .unwrap(); + let pubkey = hex::decode( + "c0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7", + ).unwrap(); let message = hex::decode("5f4c8989").unwrap(); - let signature = hex::decode("124f6fc6b0d100842769e71bd530664d888df8507df6c56dedfdb509aeb93416e26b918d38aa06305df3095697c18b2aa832eaa52edc0ae49fbae5a85e150c07") - .unwrap(); + let signature = hex::decode( + "124f6fc6b0d100842769e71bd530664d888df8507df6c56dedfdb509aeb93416e26b918d38aa06305df3095697c18b2aa832eaa52edc0ae49fbae5a85e150c07" + ).unwrap(); let mut v = Verifier::new(&pubkey); v.update(&message); @@ -129,8 +134,9 @@ mod test { let seed = hex::decode("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") .unwrap(); - let expected_sig = hex::decode("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b") - .unwrap(); + let expected_sig = hex::decode( + "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b" + ).unwrap(); let mut s = Signer::new(&seed); let sig = s.sign(); @@ -144,8 +150,9 @@ mod test { let message = hex::decode("cbc77b").unwrap(); - let expected_sig = hex::decode("d9868d52c2bebce5f3fa5a79891970f309cb6591e3e1702a70276fa97c24b3a8e58606c38c9758529da50ee31b8219cba45271c689afa60b0ea26c99db19b00c") - .unwrap(); + let expected_sig = hex::decode( + "d9868d52c2bebce5f3fa5a79891970f309cb6591e3e1702a70276fa97c24b3a8e58606c38c9758529da50ee31b8219cba45271c689afa60b0ea26c99db19b00c" + ).unwrap(); let mut s = Signer::new(&seed); s.update(&message); @@ -170,5 +177,4 @@ mod test { assert_eq!(result, true); } - } diff --git a/src/tag.rs b/src/tag.rs index 4ec02b0..2b9c1f4 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -19,7 +19,7 @@ use error::Error; pub enum Tag { // Enforcement of the "tags in strictly increasing order" rule is done using the // little-endian encoding of the ASCII tag value; e.g. 'SIG\x00' is 0x00474953 and - // 'NONC' is 0x434e4f4e. + // 'NONC' is 0x434e4f4e. // // Tags are written here in ascending order SIG, @@ -75,7 +75,7 @@ impl Tag { b"ROOT" => Ok(Tag::ROOT), b"SIG\x00" => Ok(Tag::SIG), b"SREP" => Ok(Tag::SREP), - _ => Err(Error::InvalidTag(Box::from(bytes))) + _ => Err(Error::InvalidTag(Box::from(bytes))), } } } -- cgit v1.2.3