Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

server: misc cleanups #407

Open
wants to merge 1 commit into
base: https-support
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion coordinator/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub struct Args {

/// Port to bind to, if using socket comms.
/// Port to connect to, if using HTTP mode.
#[arg(short, long, default_value_t = 2744)]
#[arg(short, long, default_value_t = 443)]
pub port: u16,
}

Expand Down
15 changes: 8 additions & 7 deletions coordinator/src/comms/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,6 @@ pub struct HTTPComms<C: Ciphersuite> {
host_port: String,
session_id: Option<Uuid>,
access_token: Option<String>,
num_signers: u16,
args: ProcessedArgs<C>,
state: SessionState<C>,
pubkeys: HashMap<Vec<u8>, Identifier<C>>,
Expand All @@ -284,7 +283,6 @@ impl<C: Ciphersuite> HTTPComms<C> {
host_port: format!("https://{}:{}", args.ip, args.port),
session_id: None,
access_token: None,
num_signers: 0,
args: args.clone(),
state: SessionState::new(args.messages.len(), args.num_signers as usize),
pubkeys: Default::default(),
Expand Down Expand Up @@ -342,7 +340,7 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
_input: &mut dyn BufRead,
_output: &mut dyn Write,
_pub_key_package: &PublicKeyPackage<C>,
num_signers: u16,
_num_signers: u16,
) -> Result<BTreeMap<Identifier<C>, SigningCommitments<C>>, Box<dyn Error>> {
let mut rng = thread_rng();
let challenge = self
Expand Down Expand Up @@ -370,7 +368,7 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
self.client
.post(format!("{}/login", self.host_port))
.json(&server::KeyLoginArgs {
uuid: challenge,
challenge,
pubkey: self
.args
.comm_pubkey
Expand All @@ -391,8 +389,12 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
.post(format!("{}/create_new_session", self.host_port))
.bearer_auth(self.access_token.as_ref().expect("was just set"))
.json(&server::CreateNewSessionArgs {
pubkeys: self.args.signers.clone(),
num_signers,
pubkeys: self
.args
.signers
.iter()
.map(|p| server::PublicKey(p.clone()))
.collect(),
message_count: 1,
})
.send()
Expand All @@ -407,7 +409,6 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
);
}
self.session_id = Some(r.session_id);
self.num_signers = num_signers;

// If encryption is enabled, create the Noise objects
(self.send_noise, self.recv_noise) = if let (
Expand Down
2 changes: 1 addition & 1 deletion participant/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub struct Args {
pub ip: String,

/// Port to connect to, if using online comms
#[arg(short, long, default_value_t = 2744)]
#[arg(short, long, default_value_t = 443)]
pub port: u16,

/// Optional Session ID
Expand Down
2 changes: 1 addition & 1 deletion participant/src/comms/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ where
self.client
.post(format!("{}/login", self.host_port))
.json(&server::KeyLoginArgs {
uuid: challenge,
challenge,
pubkey: self
.args
.comm_pubkey
Expand Down
1 change: 1 addition & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ derivative = "2.2.0"
eyre = "0.6.11"
frost-core = { version = "2.0.0", features = ["serde"] }
frost-rerandomized = { version = "2.0.0-rc.0", features = ["serde"] }
hex = "0.4"
password-auth = "1.0.0"
rand = "0.8"
rcgen = "0.13.1"
Expand Down
29 changes: 11 additions & 18 deletions server/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# FROST Server


This is a HTTP server that allow clients (Coordinator and Participants) to
run FROST without needing to directly connect to one another.
This is a JSON-HTTPS server that allow FROST clients (Coordinator and
Participants) to run FROST without needing to directly connect to one another.


## Status ⚠

This is a prototype which is NOT SECURE since messages are not encrypted nor
authenticated. DO NOT USE this for anything other than testing.
This project has not being audited.


## Usage
Expand All @@ -17,19 +15,14 @@ NOTE: This is for demo purposes only and should not be used in production.

You will need to have [Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) installed.

To run:
1. Clone the repo. Run `git clone https://github.com/ZcashFoundation/frost-zcash-demo.git`
2. Run `cargo install`
3. Run `cargo run --bin server`
To compile and run:

You can specify the IP and port to bind to using `--ip` and `--port`, e.g.
`cargo run --bin server -- --ip 127.0.0.1 --port 2744`.
1. Clone the repo. Run `git clone https://github.com/ZcashFoundation/frost-zcash-demo.git`
2. Run `cargo build --release --bin server`
3. Run `./target/release/server -h` to learn about the command line arguments.

## TODO
You will need to specify a TLS certificate and key with the `--tls-cert`
and `--tls-key` arguments.

- Add specific error codes
- Remove frost-specific types (when data is encrypted)
- Session timeouts
- Encryption/authentication
- DoS protections and other production-ready requirements
-
For more details on using and deploying, refer to the [ZF FROST
Book](https://frost.zfnd.org/).
34 changes: 18 additions & 16 deletions server/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
};

/// Implement the challenge API.
#[tracing::instrument(ret, err(Debug), skip(state, _args))]
#[tracing::instrument(level = "debug", err(Debug), skip(state, _args))]
pub(crate) async fn challenge(
State(state): State<SharedState>,
Json(_args): Json<ChallengeArgs>,
Expand All @@ -26,7 +26,7 @@ pub(crate) async fn challenge(
}

/// Implement the key_login API.
#[tracing::instrument(ret, err(Debug), skip(state, args))]
#[tracing::instrument(level = "debug", err(Debug), skip(state, args))]
pub(crate) async fn login(
State(state): State<SharedState>,
Json(args): Json<KeyLoginArgs>,
Expand All @@ -53,11 +53,11 @@ pub(crate) async fn login(
)
})?;
pubkey
.verify(args.uuid.as_bytes(), &signature)
.verify(args.challenge.as_bytes(), &signature)
.map_err(|_| AppError(StatusCode::UNAUTHORIZED, eyre!("invalid signature").into()))?;

let mut challenges = state.challenges.write().unwrap();
if !challenges.remove(&args.uuid) {
if !challenges.remove(&args.challenge) {
return Err(AppError(
StatusCode::UNAUTHORIZED,
eyre!("invalid challenge").into(),
Expand All @@ -76,7 +76,7 @@ pub(crate) async fn login(
}

/// Implement the logout API.
#[tracing::instrument(ret, err(Debug), skip(state, user))]
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
pub(crate) async fn logout(
State(state): State<SharedState>,
user: User,
Expand All @@ -90,7 +90,7 @@ pub(crate) async fn logout(
}

/// Implement the create_new_session API.
#[tracing::instrument(ret, err(Debug), skip(state, user))]
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
pub(crate) async fn create_new_session(
State(state): State<SharedState>,
user: User,
Expand All @@ -112,15 +112,14 @@ pub(crate) async fn create_new_session(
for pubkey in &args.pubkeys {
state
.sessions_by_pubkey
.entry(pubkey.clone())
.entry(pubkey.clone().0)
.or_default()
.insert(id);
}
// Create Session object
let session = Session {
pubkeys: args.pubkeys,
pubkeys: args.pubkeys.into_iter().map(|p| p.0).collect(),
coordinator_pubkey: user.pubkey,
num_signers: args.num_signers,
message_count: args.message_count,
queue: Default::default(),
};
Expand All @@ -132,7 +131,7 @@ pub(crate) async fn create_new_session(
}

/// Implement the create_new_session API.
#[tracing::instrument(ret, err(Debug), skip(state, user))]
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
pub(crate) async fn list_sessions(
State(state): State<SharedState>,
user: User,
Expand All @@ -149,7 +148,7 @@ pub(crate) async fn list_sessions(
}

/// Implement the get_session_info API
#[tracing::instrument(ret, err(Debug), skip(state, user))]
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
pub(crate) async fn get_session_info(
State(state): State<SharedState>,
user: User,
Expand Down Expand Up @@ -178,16 +177,19 @@ pub(crate) async fn get_session_info(
))?;

Ok(Json(GetSessionInfoOutput {
num_signers: session.num_signers,
message_count: session.message_count,
pubkeys: session.pubkeys.clone(),
pubkeys: session
.pubkeys
.iter()
.map(|p| PublicKey(p.clone()))
.collect(),
coordinator_pubkey: session.coordinator_pubkey.clone(),
}))
}

/// Implement the send API
// TODO: get identifier from channel rather from arguments
#[tracing::instrument(ret, err(Debug), skip(state, user))]
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
pub(crate) async fn send(
State(state): State<SharedState>,
user: User,
Expand Down Expand Up @@ -225,7 +227,7 @@ pub(crate) async fn send(

/// Implement the recv API
// TODO: get identifier from channel rather from arguments
#[tracing::instrument(ret, err(Debug), skip(state, user))]
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
pub(crate) async fn receive(
State(state): State<SharedState>,
user: User,
Expand Down Expand Up @@ -254,7 +256,7 @@ pub(crate) async fn receive(
}

/// Implement the close_session API.
#[tracing::instrument(ret, err(Debug), skip(state, user))]
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
pub(crate) async fn close_session(
State(state): State<SharedState>,
user: User,
Expand Down
7 changes: 4 additions & 3 deletions server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ pub async fn run(args: &Args) -> Result<(), Box<dyn std::error::Error>> {

if args.no_tls_very_insecure {
tracing::warn!(
"starting an INSECURE HTTP server. This should be done only for \
testing or if you are providing TLS/HTTPS with a separate \
mechanism (e.g. reverse proxy such as nginx)"
"starting an INSECURE HTTP server at {}. This should be done only \
for testing or if you are providing TLS/HTTPS with a separate \
mechanism (e.g. reverse proxy such as nginx)",
addr,
);
let listener = tokio::net::TcpListener::bind(addr).await?;
Ok(axum::serve(listener, app).await?)
Expand Down
10 changes: 9 additions & 1 deletion server/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
use clap::Parser;
use server::args::Args;
use server::run;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::EnvFilter;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
// initialize tracing
tracing_subscriber::fmt::init();
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.init();
tracing::event!(tracing::Level::INFO, "server running");
run(&args).await
}
2 changes: 0 additions & 2 deletions server/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ pub struct Session {
pub(crate) pubkeys: Vec<Vec<u8>>,
/// The public key of the coordinator
pub(crate) coordinator_pubkey: Vec<u8>,
/// The number of signers in the session.
pub(crate) num_signers: u16,
/// The set of identifiers for the session.
// pub(crate) identifiers: BTreeSet<SerializedIdentifier>,
/// The number of messages being simultaneously signed.
Expand Down
16 changes: 10 additions & 6 deletions server/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct ChallengeOutput {

#[derive(Debug, Serialize, Deserialize)]
pub struct KeyLoginArgs {
pub uuid: Uuid,
pub challenge: Uuid,
#[serde(
serialize_with = "serdect::slice::serialize_hex_lower_or_bin",
deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec"
Expand Down Expand Up @@ -57,8 +57,7 @@ pub struct LoginArgs {

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CreateNewSessionArgs {
pub pubkeys: Vec<Vec<u8>>,
pub num_signers: u16,
pub pubkeys: Vec<PublicKey>,
pub message_count: u8,
}

Expand All @@ -79,13 +78,12 @@ pub struct GetSessionInfoArgs {

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GetSessionInfoOutput {
pub num_signers: u16,
pub message_count: u8,
pub pubkeys: Vec<Vec<u8>>,
pub pubkeys: Vec<PublicKey>,
pub coordinator_pubkey: Vec<u8>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct PublicKey(
#[serde(
Expand All @@ -95,6 +93,12 @@ pub struct PublicKey(
pub Vec<u8>,
);

impl std::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&hex::encode(&self.0))
}
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SendArgs {
pub session_id: Uuid,
Expand Down
Loading