keystore v2 work
This commit is contained in:
parent
bafc361e76
commit
e901f63bb9
|
@ -17,10 +17,11 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use sea_orm::{ActiveModelTrait, EntityTrait};
|
use sea_orm::{ActiveModelTrait, EntityTrait};
|
||||||
use trifid_pki::cert::{deserialize_ed25519_public, deserialize_x25519_public};
|
use trifid_pki::cert::{deserialize_ed25519_public, deserialize_x25519_public};
|
||||||
use trifid_pki::x25519_dalek::PublicKey;
|
use trifid_pki::x25519_dalek::PublicKey;
|
||||||
use trifid_api_entities::entity::host;
|
use trifid_api_entities::entity::{host, keystore_entry, keystore_host};
|
||||||
use crate::error::APIErrorsResponse;
|
use crate::error::APIErrorsResponse;
|
||||||
use sea_orm::{ColumnTrait, QueryFilter, IntoActiveModel};
|
use sea_orm::{ColumnTrait, QueryFilter, IntoActiveModel};
|
||||||
use sea_orm::ActiveValue::Set;
|
use sea_orm::ActiveValue::Set;
|
||||||
|
use trifid_api_entities::entity::prelude::KeystoreHost;
|
||||||
|
|
||||||
#[post("/v1/dnclient")]
|
#[post("/v1/dnclient")]
|
||||||
pub async fn dnclient(
|
pub async fn dnclient(
|
||||||
|
@ -54,8 +55,18 @@ pub async fn dnclient(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let host_in_ks = keystore.hosts.iter_mut().find(|u| &u.id == host);
|
let host_in_ks = match keystore_host::Entity::find().filter(keystore_host::Column::Id.eq(host)).one(&db.conn).await {
|
||||||
let host_in_ks = match host_in_ks {
|
Ok(maybe_host) => maybe_host,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(vec![APIError {
|
||||||
|
code: "ERR_DB_ERROR".to_string(),
|
||||||
|
message: "There was an error finding the keys for your host, please contact your administrator".to_string(),
|
||||||
|
path: None
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let keystore_header = match host_in_ks {
|
||||||
Some(host) => host,
|
Some(host) => host,
|
||||||
None => {
|
None => {
|
||||||
return HttpResponse::Unauthorized().json(vec![APIError {
|
return HttpResponse::Unauthorized().json(vec![APIError {
|
||||||
|
@ -63,18 +74,36 @@ pub async fn dnclient(
|
||||||
message: "The host does not exist or you do not have permission to access it."
|
message: "The host does not exist or you do not have permission to access it."
|
||||||
.to_string(),
|
.to_string(),
|
||||||
path: None,
|
path: None,
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let counter = keystore_header.counter;
|
||||||
|
|
||||||
|
// pull their key information
|
||||||
|
|
||||||
|
let key_info = match keystore_entry::Entity::find().filter(keystore_entry::Column::Host.eq(&keystore_header.id)).one(&db.conn).await {
|
||||||
|
Ok(maybe_keys) => maybe_keys,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(vec![APIError {
|
||||||
|
code: "ERR_DB_ERROR".to_string(),
|
||||||
|
message: "There was an error finding the keys for your host, please contact your administrator".to_string(),
|
||||||
|
path: None
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let client_keys = host_in_ks
|
let keystore_data = match key_info {
|
||||||
.client_keys
|
Some(key_info) => key_info,
|
||||||
.iter()
|
None => {
|
||||||
.find(|u| u.id == req.counter as u64);
|
return HttpResponse::Unauthorized().json(vec![APIError {
|
||||||
let client_keys_2 = host_in_ks
|
code: "ERR_HOST_ERROR".to_string(),
|
||||||
.client_keys
|
message: "The host does not exist or you do not have permission to access it."
|
||||||
.iter()
|
.to_string(),
|
||||||
.find(|u| u.id == host_in_ks.current_client_key);
|
path: None,
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let signature = match Signature::from_slice(&req.signature) {
|
let signature = match Signature::from_slice(&req.signature) {
|
||||||
Ok(sig) => sig,
|
Ok(sig) => sig,
|
||||||
|
@ -90,27 +119,9 @@ pub async fn dnclient(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut valid = false;
|
let key = VerifyingKey::from(keystore_data.client_signing_key.try_into().unwrap());
|
||||||
let mut valid_key = None;
|
|
||||||
|
|
||||||
if let Some(client_keys) = client_keys {
|
if !key.verify(&req.message.as_bytes(), &signature).is_ok() {
|
||||||
if client_keys.ed_pub.verify(req.message.as_bytes(), &signature).is_ok() {
|
|
||||||
valid = true;
|
|
||||||
valid_key = Some(client_keys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(client_keys_2) = client_keys_2 {
|
|
||||||
if client_keys_2.ed_pub.verify(req.message.as_bytes(), &signature).is_ok() {
|
|
||||||
valid = true;
|
|
||||||
valid_key = Some(client_keys_2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if client_keys.is_none() && client_keys_2.is_none() {
|
|
||||||
panic!("No valid keys for host {}", host);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !valid {
|
|
||||||
// Be intentionally vague as the message is invalid.
|
// Be intentionally vague as the message is invalid.
|
||||||
warn!("! invalid signature from {}", host);
|
warn!("! invalid signature from {}", host);
|
||||||
return HttpResponse::Unauthorized().json(vec![APIError {
|
return HttpResponse::Unauthorized().json(vec![APIError {
|
||||||
|
@ -121,8 +132,6 @@ pub async fn dnclient(
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let client_keys = valid_key.unwrap();
|
|
||||||
|
|
||||||
// Sig OK
|
// Sig OK
|
||||||
// Decode the message from base64
|
// Decode the message from base64
|
||||||
|
|
||||||
|
@ -190,7 +199,7 @@ pub async fn dnclient(
|
||||||
|
|
||||||
// Do a config build
|
// Do a config build
|
||||||
|
|
||||||
let info = match collect_info(&db, host, client_keys.dh_pub.as_bytes()).await {
|
let info = match collect_info(&db, host, &keystore_data.client_dh_key).await {
|
||||||
Ok(i) => i,
|
Ok(i) => i,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return HttpResponse::InternalServerError().json(EnrollResponse::Error {
|
return HttpResponse::InternalServerError().json(EnrollResponse::Error {
|
||||||
|
@ -218,13 +227,10 @@ pub async fn dnclient(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let current_cfg = host_in_ks
|
let current_cfg = keystore_data.config;
|
||||||
.config
|
let generated_config_string = serde_yaml::to_string(&cfg).unwrap();
|
||||||
.iter()
|
|
||||||
.find(|u| u.id == host_in_ks.current_config);
|
|
||||||
|
|
||||||
let config_update_avail = current_cfg.map(|u| u.config.clone()) != Some(cfg.clone())
|
let config_update_avail = current_cfg != generated_config_string || req.counter < keystore_header.counter as u32;
|
||||||
|| req.counter < host_in_ks.current_config as u32;
|
|
||||||
|
|
||||||
host_am.last_out_of_date = Set(config_update_avail);
|
host_am.last_out_of_date = Set(config_update_avail);
|
||||||
host_am.last_seen_at = Set(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64);
|
host_am.last_seen_at = Set(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64);
|
||||||
|
@ -315,7 +321,7 @@ pub async fn dnclient(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ks = host_in_ks;
|
let ks = keystore_header;
|
||||||
|
|
||||||
ks.certs.push(KSCert {
|
ks.certs.push(KSCert {
|
||||||
id: ks.current_cert + 1,
|
id: ks.current_cert + 1,
|
||||||
|
|
Loading…
Reference in New Issue