diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index 1fec8e5..7074b84 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -1,7 +1,7 @@ - + postgresql true org.postgresql.Driver diff --git a/Cargo.lock b/Cargo.lock index b939bca..232d3b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "dnapi-rs" -version = "0.2.2" +version = "0.2.3" dependencies = [ "base64 0.21.5", "base64-serde", diff --git a/dnapi-rs/Cargo.toml b/dnapi-rs/Cargo.toml index 39572c2..b1da554 100644 --- a/dnapi-rs/Cargo.toml +++ b/dnapi-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dnapi-rs" -version = "0.2.2" +version = "0.2.3" edition = "2021" description = "A rust client for the Defined Networking API" license = "AGPL-3.0-or-later" diff --git a/dnapi-rs/src/client_async.rs b/dnapi-rs/src/client_async.rs index 8ced750..52ef34d 100644 --- a/dnapi-rs/src/client_async.rs +++ b/dnapi-rs/src/client_async.rs @@ -13,6 +13,7 @@ use log::{debug, error}; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use std::error::Error; +use reqwest::header::HeaderValue; use trifid_pki::cert::serialize_ed25519_public; use trifid_pki::ed25519_dalek::{Signature, Signer, SigningKey, Verifier}; use url::Url; @@ -89,10 +90,15 @@ impl Client { .send() .await?; + let empty_hval; + #[allow(clippy::unwrap_used)] { + empty_hval = HeaderValue::from_str("").unwrap(); + }; + let req_id = resp .headers() .get("X-Request-ID") - .ok_or("Response missing X-Request-ID")? + .unwrap_or(&empty_hval) .to_str()?; debug!("enrollment request complete {{req_id: {}}}", req_id); diff --git a/dnapi-rs/src/client_blocking.rs b/dnapi-rs/src/client_blocking.rs index 676d328..96e3a48 100644 --- a/dnapi-rs/src/client_blocking.rs +++ b/dnapi-rs/src/client_blocking.rs @@ -13,6 +13,7 @@ use log::{debug, error, trace}; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use std::error::Error; +use reqwest::header::HeaderValue; use trifid_pki::cert::serialize_ed25519_public; use trifid_pki::ed25519_dalek::{Signature, Signer, SigningKey, Verifier}; use url::Url; @@ -90,10 +91,15 @@ impl Client { .body(req_json) .send()?; + let empty_hval; + #[allow(clippy::unwrap_used)] { + empty_hval = HeaderValue::from_str("").unwrap(); + }; + let req_id = resp .headers() .get("X-Request-ID") - .ok_or("Response missing X-Request-ID")? + .unwrap_or(&empty_hval) .to_str()?; debug!("enrollment request complete {{req_id: {}}}", req_id); diff --git a/tfclient/src/nebulaworker.rs b/tfclient/src/nebulaworker.rs index 5e0eaad..260c5d9 100644 --- a/tfclient/src/nebulaworker.rs +++ b/tfclient/src/nebulaworker.rs @@ -28,7 +28,7 @@ fn insert_private_key(instance: &str) -> Result<(), Box> { config.pki.key = Some(String::from_utf8(key)?); - debug!("inserted private key into config: {:?}", config); + debug!("inserted private key into config"); let config_str = serde_yaml::to_string(&config)?; fs::write(nebula_yml(instance), config_str)?; diff --git a/trifid-api/src/auth.rs b/trifid-api/src/auth.rs index fbb019d..9653222 100644 --- a/trifid-api/src/auth.rs +++ b/trifid-api/src/auth.rs @@ -1,8 +1,8 @@ -use crate::models::SessionToken; +use crate::models::{AuthToken, SessionToken}; pub struct AuthInfo { pub session_token: Option, - pub auth_token: Option<()>, + pub auth_token: Option, } #[macro_export] @@ -52,7 +52,24 @@ macro_rules! auth { auth_info.session_token = Some(real_token.clone()); } else if token.starts_with("auth-") { // parse auth token - todo!() + + use $crate::schema::auth_tokens::dsl::*; + + let tokens = $crate::handle_error!( + auth_tokens + .filter(id.eq(token)) + .select($crate::models::AuthToken::as_select()) + .load(&mut $c) + .await + ); + let real_token = match tokens.get(0) { + Some(tok) => tok, + None => $crate::err!( + actix_web::http::StatusCode::UNAUTHORIZED, + $crate::make_err!("ERR_UNAUTHORIZED", "unauthorized") + ), + }; + auth_info.auth_token = Some(real_token.clone()); } } auth_info diff --git a/trifid-api/src/config_generator.rs b/trifid-api/src/config_generator.rs index 384b561..7a0f0ec 100644 --- a/trifid-api/src/config_generator.rs +++ b/trifid-api/src/config_generator.rs @@ -65,7 +65,7 @@ pub async fn generate_config( let mut ca_string = String::new(); for ca in cas { - if ca.expires_at < SystemTime::now() { + if ca.expires_at > SystemTime::now() { let ca_cert: NebulaCertificate = serde_json::from_value(ca.cert.clone()).map_err(ConfigGenError::InvalidCACert)?; ca_string += &String::from_utf8_lossy( diff --git a/trifid-api/src/main.rs b/trifid-api/src/main.rs index ddcf946..9b013e4 100644 --- a/trifid-api/src/main.rs +++ b/trifid-api/src/main.rs @@ -2,6 +2,7 @@ use crate::config::Config; use crate::error::APIErrorResponse; use actix_web::middleware::Logger; use actix_web::web::{Data, JsonConfig}; +use actix_web::dev::Service; use actix_web::{App, Error, HttpResponse, HttpServer}; use diesel::Connection; use diesel_async::async_connection_wrapper::AsyncConnectionWrapper; @@ -12,6 +13,8 @@ use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; use log::{error, info}; use std::fs; use std::path::PathBuf; +use actix_web::http::header::{HeaderName, HeaderValue}; +use std::str::FromStr; pub mod error; #[macro_use] @@ -138,10 +141,22 @@ async fn main() { .service(routes::v1::auth::verify_magic_link::verify_link_req) .service(routes::v1::auth::magic_link::login_req) .service(routes::v1::totp_authenticators::create_totp_auth_req) - .service(routes::v1::verify_totp_authenticator::verify_totp_req) + .service(routes::v1::verify_totp_authenticators::verify_totp_req) .service(routes::v1::auth::totp::totp_req) + .service(routes::v1::dnclient::dnclient_req) + .service(routes::v1::networks::create_network_req) + .service(routes::v2::enroll::enroll_req) .wrap(Logger::default()) .wrap(actix_cors::Cors::permissive()) + .wrap_fn(|req, srv| { + let fut = srv.call(req); + async { + let mut res = fut.await?; + res.headers_mut() + .insert(HeaderName::from_str("X-Request-ID").unwrap(), HeaderValue::from_str(&randid!(id "")).unwrap()); + Ok(res) + } + }) .app_data(app_state.clone()) }) .bind((local_config.server.bind.ip, local_config.server.bind.port)) diff --git a/trifid-api/src/routes/v1/dnclient.rs b/trifid-api/src/routes/v1/dnclient.rs index f36e2d2..3121841 100644 --- a/trifid-api/src/routes/v1/dnclient.rs +++ b/trifid-api/src/routes/v1/dnclient.rs @@ -16,18 +16,22 @@ use dnapi_rs::message::{ use log::warn; use serde::Serialize; use std::time::SystemTime; +use actix_web::post; use trifid_pki::cert::{ deserialize_ed25519_public, deserialize_x25519_public, serialize_ed25519_public, }; use trifid_pki::ed25519_dalek::{Signature, Verifier, VerifyingKey}; use trifid_pki::x25519_dalek::PublicKey; +use crate::crypt::DnclientKeyLockbox; #[derive(Serialize, Debug)] +#[serde(untagged)] pub enum DnclientResponse { CheckForUpdateResp(CheckForUpdateResponseWrapper), DoUpdateResp(SignedResponseWrapper), } +#[post("/v1/dnclient")] pub async fn dnclient_req( req: Json, state: Data, @@ -53,7 +57,7 @@ pub async fn dnclient_req( .await .optional()); - let key = match maybe_key { + let host_key = match maybe_key { Some(k) => k, None => { err!( @@ -67,8 +71,9 @@ pub async fn dnclient_req( }; let signature = handle_error!(Signature::from_slice(&req.signature)); + let ed_pub = deserialize_ed25519_public(&host_key.client_ed_pub).unwrap(); let key = handle_error!(VerifyingKey::from_bytes( - &key.client_ed_pub.try_into().unwrap() + &ed_pub.try_into().unwrap() )); if key.verify(req.message.as_bytes(), &signature).is_err() { @@ -139,7 +144,7 @@ pub async fn dnclient_req( id: randid!(id "hostkey"), host_id: host.id.clone(), counter: new_counter, - client_ed_pub: new_ed_key, + client_ed_pub: do_update_req.ed_pubkey_pem, client_dh_pub: new_dh_pub_bytes, client_cert: new_config.pki.cert.as_bytes().to_vec(), salt: key_lockbox.nonce.clone(), @@ -176,10 +181,16 @@ pub async fn dnclient_req( let msg_bytes = handle_error!(serde_json::to_vec(&msg)); + let old_key_lockbox = DnclientKeyLockbox { + nonce: host_key.salt.clone(), + info: host_key.info.clone(), + key: host_key.server_ed_priv.clone() + }; + let resp = SignedResponse { version: 1, message: msg_bytes.clone(), - signature: sign_dnclient_with_lockbox(&key_lockbox, &msg_bytes, &state.config) + signature: sign_dnclient_with_lockbox(&old_key_lockbox, &msg_bytes, &state.config) .unwrap().to_vec(), }; diff --git a/trifid-api/src/routes/v1/mod.rs b/trifid-api/src/routes/v1/mod.rs index 5bd018b..3632916 100644 --- a/trifid-api/src/routes/v1/mod.rs +++ b/trifid-api/src/routes/v1/mod.rs @@ -3,4 +3,4 @@ pub mod dnclient; pub mod networks; pub mod signup; pub mod totp_authenticators; -pub mod verify_totp_authenticator; +pub mod verify_totp_authenticators; diff --git a/trifid-api/src/routes/v1/networks.rs b/trifid-api/src/routes/v1/networks.rs index c88c40d..28dd2cd 100644 --- a/trifid-api/src/routes/v1/networks.rs +++ b/trifid-api/src/routes/v1/networks.rs @@ -7,7 +7,7 @@ use crate::schema::signing_cas::dsl::signing_cas; use crate::schema::users; use crate::{auth, enforce, randid, AppState}; use actix_web::web::{Data, Json}; -use actix_web::HttpRequest; +use actix_web::{HttpRequest, post}; use chrono::{DateTime, SecondsFormat, Utc}; use diesel::{ExpressionMethods, QueryDsl, SelectableHelper}; use diesel_async::RunQueryDsl; @@ -25,6 +25,7 @@ pub struct CreateNetworkResp { pub data: NetworkNormalized, } +#[post("/v1/networks")] pub async fn create_network_req( req: Json, state: Data, diff --git a/trifid-api/src/routes/v1/verify_totp_authenticator.rs b/trifid-api/src/routes/v1/verify_totp_authenticators.rs similarity index 98% rename from trifid-api/src/routes/v1/verify_totp_authenticator.rs rename to trifid-api/src/routes/v1/verify_totp_authenticators.rs index 2bcf769..6d9562e 100644 --- a/trifid-api/src/routes/v1/verify_totp_authenticator.rs +++ b/trifid-api/src/routes/v1/verify_totp_authenticators.rs @@ -33,7 +33,7 @@ pub struct TotpAuthResp { pub metadata: TotpAuthRespMeta, } -#[post("/v1/verify-totp-authenticator")] +#[post("/v1/verify-totp-authenticators")] pub async fn verify_totp_req( req: Json, state: Data, diff --git a/trifid-api/src/routes/v2/enroll.rs b/trifid-api/src/routes/v2/enroll.rs index b10d0bb..cded0e5 100644 --- a/trifid-api/src/routes/v2/enroll.rs +++ b/trifid-api/src/routes/v2/enroll.rs @@ -12,9 +12,11 @@ use diesel::{ExpressionMethods, OptionalExtension, QueryDsl}; use diesel_async::RunQueryDsl; use dnapi_rs::message::{EnrollRequest, EnrollResponse, EnrollResponseData, EnrollResponseDataOrg}; use std::time::SystemTime; -use trifid_pki::cert::serialize_ed25519_public; +use actix_web::post; +use trifid_pki::cert::{deserialize_x25519_public, serialize_ed25519_public}; use trifid_pki::x25519_dalek::PublicKey; +#[post("/v2/enroll")] pub async fn enroll_req( req: Json, state: Data, @@ -84,7 +86,9 @@ pub async fn enroll_req( let (key_lockbox, trusted_key) = handle_error!(create_dnclient_ed_key(&state.config)); - let fixed_dh_key: [u8; 32] = req.dh_pubkey.clone().try_into().unwrap(); + let dh_pubkey = deserialize_x25519_public(&req.dh_pubkey).unwrap(); + + let fixed_dh_key: [u8; 32] = dh_pubkey.clone().try_into().unwrap(); let user_dh_key = PublicKey::from(fixed_dh_key);