keystore v2 probably done

This commit is contained in:
core 2023-08-18 23:55:27 -04:00
parent 3dadd40bba
commit 810b87986b
Signed by: core
GPG Key ID: FDBF740DADDCEECF
6 changed files with 167 additions and 197 deletions

View File

@ -12,17 +12,13 @@ use crate::config::{
NebulaConfigRelay, NebulaConfigTun, CONFIG, NebulaConfigRelay, NebulaConfigTun, CONFIG,
}; };
use crate::crypto::{decrypt_with_nonce, get_cipher_from_config}; use crate::crypto::{decrypt_with_nonce, get_cipher_from_config};
use crate::keystore::keystore_init;
use crate::AppState; use crate::AppState;
use ed25519_dalek::SigningKey; use ed25519_dalek::SigningKey;
use ipnet::Ipv4Net; use ipnet::Ipv4Net;
use log::{error}; use log::{error};
use sea_orm::{ColumnTrait, Condition, EntityTrait, QueryFilter}; use sea_orm::{ColumnTrait, Condition, EntityTrait, QueryFilter};
use serde_yaml::{Mapping, Value}; use serde_yaml::{Mapping, Value};
use trifid_api_entities::entity::{ use trifid_api_entities::entity::{firewall_rule, host, host_config_override, host_static_address, keystore_entry, network, organization, signing_ca};
firewall_rule, host, host_config_override, host_static_address, network, organization,
signing_ca,
};
use trifid_pki::cert::{ use trifid_pki::cert::{
deserialize_ed25519_private, deserialize_nebula_certificate_from_pem, NebulaCertificate, deserialize_ed25519_private, deserialize_nebula_certificate_from_pem, NebulaCertificate,
NebulaCertificateDetails, NebulaCertificateDetails,
@ -44,7 +40,7 @@ pub struct CodegenRequiredInfo {
} }
pub async fn generate_config( pub async fn generate_config(
_data: &Data<AppState>, db: &Data<AppState>,
info: &CodegenRequiredInfo, info: &CodegenRequiredInfo,
) -> Result<(NebulaConfig, NebulaCertificate), Box<dyn Error>> { ) -> Result<(NebulaConfig, NebulaCertificate), Box<dyn Error>> {
// decode the CA data // decode the CA data
@ -90,14 +86,22 @@ pub async fn generate_config(
} }
cas += &String::from_utf8(hex::decode(&info.ca.cert)?)?; cas += &String::from_utf8(hex::decode(&info.ca.cert)?)?;
let ks = keystore_init()?;
// blocked hosts // blocked hosts
let mut blocked_hosts_fingerprints = vec![]; let mut blocked_hosts_fingerprints = vec![];
for host in &info.blocked_hosts { for host in &info.blocked_hosts {
if let Some(host) = ks.hosts.iter().find(|u| &u.id == host) {
for cert in &host.certs { // check if the host exists
blocked_hosts_fingerprints.push(cert.cert.sha256sum()?); if host::Entity::find().filter(host::Column::Id.eq(host)).one(&db.conn).await?.is_some() {
// pull all of their certs ever and block them
let host_entries = keystore_entry::Entity::find().filter(keystore_entry::Column::Host.eq(host)).all(&db.conn).await?;
for entry in &host_entries {
// decode the cert
let cert = deserialize_nebula_certificate_from_pem(&entry.certificate)?;
blocked_hosts_fingerprints.push(cert.sha256sum()?);
} }
} }
} }

View File

@ -26,7 +26,6 @@ use std::time::Duration;
use actix_cors::Cors; use actix_cors::Cors;
use crate::config::CONFIG; use crate::config::CONFIG;
use crate::error::{APIError, APIErrorsResponse}; use crate::error::{APIError, APIErrorsResponse};
use crate::keystore::keystore_init;
use crate::tokens::random_id_no_id; use crate::tokens::random_id_no_id;
use trifid_api_migration::{Migrator, MigratorTrait}; use trifid_api_migration::{Migrator, MigratorTrait};
@ -36,11 +35,12 @@ pub mod config;
pub mod crypto; pub mod crypto;
pub mod cursor; pub mod cursor;
pub mod error; pub mod error;
pub mod keystore; //pub mod legacy_keystore; // TODO- Remove
pub mod magic_link; pub mod magic_link;
pub mod routes; pub mod routes;
pub mod timers; pub mod timers;
pub mod tokens; pub mod tokens;
pub mod response;
pub struct AppState { pub struct AppState {
pub conn: DatabaseConnection, pub conn: DatabaseConnection,
@ -50,10 +50,6 @@ pub struct AppState {
async fn main() -> Result<(), Box<dyn Error>> { async fn main() -> Result<(), Box<dyn Error>> {
simple_logger::init_with_level(Level::Debug).unwrap(); simple_logger::init_with_level(Level::Debug).unwrap();
info!("Creating keystore...");
let _keystore = keystore_init()?;
info!("Connecting to database at {}...", CONFIG.database.url); info!("Connecting to database at {}...", CONFIG.database.url);
let mut opt = ConnectOptions::new(CONFIG.database.url.clone()); let mut opt = ConnectOptions::new(CONFIG.database.url.clone());

View File

@ -0,0 +1,51 @@
use std::fmt::{Display, Formatter};
use actix_web::{HttpRequest, HttpResponse, Responder, ResponseError};
use actix_web::body::EitherBody;
use actix_web::web::Json;
use log::error;
use sea_orm::DbErr;
use serde::Serialize;
use crate::error::{APIError, APIErrorsResponse};
pub struct OkResponse<T: Responder>(T);
#[derive(Debug)]
pub struct ErrResponse(APIErrorsResponse);
impl<T: Responder> Responder for OkResponse<T> {
type Body = T::Body;
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
self.0.respond_to(req)
}
}
impl Responder for ErrResponse {
type Body = EitherBody<String>;
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
Json(self.0).respond_to(req)
}
}
impl From<DbErr> for ErrResponse {
fn from(value: DbErr) -> Self {
error!("database error: {}", value);
Self {
0: APIErrorsResponse { errors: vec![
APIError {
code: "ERR_DB_ERROR".to_string(),
message: "There was an error performing the database query. Please try again later.".to_string(),
path: None,
}
] },
}
}
}
impl Display for ErrResponse {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl ResponseError for ErrResponse {}

View File

@ -1,6 +1,4 @@
use crate::codegen::{collect_info, generate_config}; use crate::codegen::{collect_info, generate_config};
use crate::keystore::{keystore_flush, keystore_init, KSCert, KSClientKey, KSConfig, KSSigningKey};
use crate::AppState;
use actix_web::web::{Data, Json}; use actix_web::web::{Data, Json};
use actix_web::{post, HttpRequest, HttpResponse}; use actix_web::{post, HttpRequest, HttpResponse};
use base64::Engine; use base64::Engine;
@ -10,10 +8,11 @@ use dnapi_rs::message::{
DoUpdateResponse, EnrollResponse, RequestV1, RequestWrapper, SignedResponse, DoUpdateResponse, EnrollResponse, RequestV1, RequestWrapper, SignedResponse,
SignedResponseWrapper, SignedResponseWrapper,
}; };
use ed25519_dalek::{Signature, Signer, Verifier, VerifyingKey}; use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
use log::{error, warn}; use log::{error, warn};
use std::clone::Clone; use std::clone::Clone;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use ed25519_dalek::ed25519::signature::Keypair;
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;
@ -21,7 +20,8 @@ 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; use crate::AppState;
use crate::tokens::random_id;
#[post("/v1/dnclient")] #[post("/v1/dnclient")]
pub async fn dnclient( pub async fn dnclient(
@ -41,20 +41,6 @@ pub async fn dnclient(
let host = &req.host_id; let host = &req.host_id;
let mut keystore = match keystore_init() {
Ok(ks) => ks,
Err(e) => {
error!("keystore load error: {}", e);
return HttpResponse::InternalServerError().json(EnrollResponse::Error {
errors: vec![APIError {
code: "ERR_KS_LOAD_ERROR".to_string(),
message: e.to_string(),
path: None,
}],
});
}
};
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 keystore_host::Entity::find().filter(keystore_host::Column::Id.eq(host)).one(&db.conn).await {
Ok(maybe_host) => maybe_host, Ok(maybe_host) => maybe_host,
Err(e) => { Err(e) => {
@ -119,7 +105,7 @@ pub async fn dnclient(
} }
}; };
let key = VerifyingKey::from(keystore_data.client_signing_key.try_into().unwrap()); let key = VerifyingKey::from_bytes(&keystore_data.client_signing_key.try_into().unwrap()).unwrap();
if !key.verify(&req.message.as_bytes(), &signature).is_ok() { if !key.verify(&req.message.as_bytes(), &signature).is_ok() {
// Be intentionally vague as the message is invalid. // Be intentionally vague as the message is invalid.
@ -321,26 +307,6 @@ pub async fn dnclient(
} }
}; };
let ks = keystore_header;
ks.certs.push(KSCert {
id: ks.current_cert + 1,
cert,
});
ks.current_cert += 1;
ks.config.push(KSConfig {
id: ks.current_config + 1,
config: cfg.clone(),
});
ks.current_config += 1;
ks.signing_keys.push(KSSigningKey {
id: ks.current_signing_key + 1,
key: ks.signing_keys[0].key.clone(),
});
ks.current_signing_key += 1;
let dh_pubkey = match deserialize_x25519_public(&do_update_req.dh_pubkey_pem) { let dh_pubkey = match deserialize_x25519_public(&do_update_req.dh_pubkey_pem) {
Ok(r) => r, Ok(r) => r,
Err(e) => { Err(e) => {
@ -365,53 +331,38 @@ pub async fn dnclient(
} }
}; };
let dh_pubkey_typed: [u8; 32] = dh_pubkey.try_into().unwrap(); let cfg_str = match serde_yaml::to_string(&cfg) {
Ok(c_str) => c_str,
ks.client_keys.push(KSClientKey {
id: ks.current_client_key + 1,
dh_pub: PublicKey::from(dh_pubkey_typed),
ed_pub: VerifyingKey::from_bytes(&ed_pubkey.try_into().unwrap()).unwrap(),
});
ks.current_client_key += 1;
let host_in_ks = ks.clone();
match keystore_flush(&keystore) {
Ok(_) => (),
Err(e) => { Err(e) => {
error!("keystore save error: {}", e); error!("config serialization error: {}", e);
return HttpResponse::InternalServerError().json(vec![APIError { return HttpResponse::InternalServerError().json(vec![APIError {
code: "ERR_SAVE_ERR".to_string(), code: "ERR_CFG_SERIALIZATION".to_string(),
message: "There was an error saving the keystore.".to_string(), message: "There was an error serializing the new configuration."
.to_string(),
path: None, path: None,
}]); }]);
} }
} };
let ks_entry_model = keystore_entry::Model {
id: random_id("ksentry"),
host: host.clone(),
counter: counter + 1,
certificate: cert.serialize_to_pem().unwrap(),
client_dh_key: dh_pubkey,
client_signing_key: ed_pubkey,
config: cfg_str.clone(),
signing_key: keystore_data.signing_key.clone()
};
let signing_key = SigningKey::from_bytes(&keystore_data.signing_key.try_into().unwrap());
// get the signing key that the client last trusted based on its current config version // get the signing key that the client last trusted based on its current config version
// this is their current counter
let signing_key = host_in_ks
.signing_keys
.iter()
.find(|u| u.id == (req.counter as u64))
.unwrap();
let msg = DoUpdateResponse { let msg = DoUpdateResponse {
config: match serde_yaml::to_string(&cfg) { config: cfg_str.as_bytes().to_vec(),
Ok(c_str) => c_str.as_bytes().to_vec(), counter: (counter + 1) as u32,
Err(e) => {
error!("config serialization error: {}", e);
return HttpResponse::InternalServerError().json(vec![APIError {
code: "ERR_CFG_SERIALIZATION".to_string(),
message: "There was an error serializing the new configuration."
.to_string(),
path: None,
}]);
}
},
counter: host_in_ks.current_config as u32,
nonce: do_update_req.nonce, nonce: do_update_req.nonce,
trusted_keys: ed25519_public_keys_to_pem(&[signing_key.key.verifying_key()]), trusted_keys: ed25519_public_keys_to_pem(&[signing_key.verifying_key()]),
}; };
let msg_bytes = match serde_json::to_vec(&msg) { let msg_bytes = match serde_json::to_vec(&msg) {
@ -430,7 +381,7 @@ pub async fn dnclient(
let resp = SignedResponse { let resp = SignedResponse {
version: 1, version: 1,
message: msg_bytes.clone(), message: msg_bytes.clone(),
signature: signing_key.key.sign(&msg_bytes).to_vec(), signature: signing_key.sign(&msg_bytes).to_vec(),
}; };
let resp_w = SignedResponseWrapper { data: resp }; let resp_w = SignedResponseWrapper { data: resp };

View File

@ -1,40 +1,39 @@
use actix_web::web::{Data, Json}; use actix_web::web::{Data, Json};
use actix_web::{post, HttpRequest, HttpResponse}; use actix_web::{post, HttpRequest, HttpResponse, Responder, ResponseError};
use base64::Engine;
use dnapi_rs::message::{ use dnapi_rs::message::{
APIError, EnrollRequest, EnrollResponse, EnrollResponseData, EnrollResponseDataOrg, APIError, EnrollRequest, EnrollResponse, EnrollResponseData, EnrollResponseDataOrg,
}; };
use ed25519_dalek::{SigningKey, VerifyingKey}; use ed25519_dalek::{SigningKey, VerifyingKey};
use log::{debug, error}; use log::{debug, error};
use rand::rngs::OsRng; use rand::rngs::OsRng;
use sea_orm::{ColumnTrait, EntityTrait, ModelTrait, QueryFilter}; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, ModelTrait, QueryFilter};
use crate::codegen::{collect_info, generate_config}; use crate::codegen::{collect_info, generate_config};
use crate::keystore::{
keystore_flush, keystore_init, KSCert, KSClientKey, KSConfig, KSSigningKey,
KeystoreHostInformation,
};
use crate::AppState; use crate::AppState;
use trifid_api_entities::entity::host_enrollment_code; use trifid_api_entities::entity::{host_enrollment_code, keystore_entry, keystore_host};
use trifid_pki::cert::{ use trifid_pki::cert::{
deserialize_ed25519_public, deserialize_x25519_public, serialize_ed25519_public, deserialize_ed25519_public, deserialize_x25519_public, serialize_ed25519_public,
}; };
use trifid_pki::x25519_dalek::PublicKey; use crate::response::ErrResponse;
use crate::timers::expired; use crate::timers::expired;
use crate::tokens::random_id;
#[post("/v2/enroll")] #[post("/v2/enroll")]
pub async fn enroll( pub async fn enroll(
req: Json<EnrollRequest>, req: Json<EnrollRequest>,
_req_info: HttpRequest, _req_info: HttpRequest,
db: Data<AppState>, db: Data<AppState>,
) -> HttpResponse { ) -> Result<impl Responder, ErrResponse> {
debug!("{:x?} {:x?}", req.dh_pubkey, req.ed_pubkey); debug!("{:x?} {:x?}", req.dh_pubkey, req.ed_pubkey);
// pull enroll information from the db // pull enroll information from the db
let code_info = match host_enrollment_code::Entity::find() let code_info = host_enrollment_code::Entity::find()
.filter(host_enrollment_code::Column::Id.eq(&req.code)) .filter(host_enrollment_code::Column::Id.eq(&req.code))
.one(&db.conn) .one(&db.conn)
.await .await?;
/*
{ {
Ok(ci) => ci, Ok(ci) => ci,
Err(e) => { Err(e) => {
@ -51,27 +50,29 @@ pub async fn enroll(
} }
}; };
*/
let enroll_info = match code_info { let enroll_info = match code_info {
Some(ei) => ei, Some(ei) => ei,
None => { None => {
return HttpResponse::Unauthorized().json(EnrollResponse::Error { return Ok(HttpResponse::Unauthorized().json(EnrollResponse::Error {
errors: vec![APIError { errors: vec![APIError {
code: "ERR_UNAUTHORIZED".to_string(), code: "ERR_UNAUTHORIZED".to_string(),
message: "That code is invalid or has expired.".to_string(), message: "That code is invalid or has expired.".to_string(),
path: None, path: None,
}], }],
}); }));
} }
}; };
if expired(enroll_info.expires_on as u64) { if expired(enroll_info.expires_on as u64) {
return HttpResponse::Unauthorized().json(EnrollResponse::Error { return Ok(HttpResponse::Unauthorized().json(EnrollResponse::Error {
errors: vec![APIError { errors: vec![APIError {
code: "ERR_UNAUTHORIZED".to_string(), code: "ERR_UNAUTHORIZED".to_string(),
message: "That code is invalid or has expired.".to_string(), message: "That code is invalid or has expired.".to_string(),
path: None, path: None,
}], }],
}); }));
} }
// deserialize // deserialize
@ -79,26 +80,26 @@ pub async fn enroll(
Ok(k) => k, Ok(k) => k,
Err(e) => { Err(e) => {
error!("public key deserialization error: {}", e); error!("public key deserialization error: {}", e);
return HttpResponse::BadRequest().json(EnrollResponse::Error { return Ok(HttpResponse::BadRequest().json(EnrollResponse::Error {
errors: vec![APIError { errors: vec![APIError {
code: "ERR_BAD_DH_PUB".to_string(), code: "ERR_BAD_DH_PUB".to_string(),
message: "Unable to deserialize the DH public key.".to_string(), message: "Unable to deserialize the DH public key.".to_string(),
path: None, path: None,
}], }],
}); }));
} }
}; };
let ed_pubkey = match deserialize_ed25519_public(&req.ed_pubkey) { let ed_pubkey = match deserialize_ed25519_public(&req.ed_pubkey) {
Ok(k) => k, Ok(k) => k,
Err(e) => { Err(e) => {
error!("public key deserialization error: {}", e); error!("public key deserialization error: {}", e);
return HttpResponse::BadRequest().json(EnrollResponse::Error { return Ok(HttpResponse::BadRequest().json(EnrollResponse::Error {
errors: vec![APIError { errors: vec![APIError {
code: "ERR_BAD_ED_PUB".to_string(), code: "ERR_BAD_ED_PUB".to_string(),
message: "Unable to deserialize the ED25519 public key.".to_string(), message: "Unable to deserialize the ED25519 public key.".to_string(),
path: None, path: None,
}], }],
}); }));
} }
}; };
@ -108,7 +109,7 @@ pub async fn enroll(
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
error!("database error: {}", e); error!("database error: {}", e);
return HttpResponse::InternalServerError().json(EnrollResponse::Error { return Ok(HttpResponse::InternalServerError().json(EnrollResponse::Error {
errors: vec![APIError { errors: vec![APIError {
code: "ERR_DB_ERROR".to_string(), code: "ERR_DB_ERROR".to_string(),
message: message:
@ -116,20 +117,20 @@ pub async fn enroll(
.to_string(), .to_string(),
path: None, path: None,
}], }],
}); }));
} }
} }
let info = match collect_info(&db, &enroll_info.host, &dh_pubkey).await { let info = match collect_info(&db, &enroll_info.host, &dh_pubkey).await {
Ok(i) => i, Ok(i) => i,
Err(e) => { Err(e) => {
return HttpResponse::InternalServerError().json(EnrollResponse::Error { return Ok(HttpResponse::InternalServerError().json(EnrollResponse::Error {
errors: vec![APIError { errors: vec![APIError {
code: "ERR_CFG_GENERATION_ERROR".to_string(), code: "ERR_CFG_GENERATION_ERROR".to_string(),
message: e.to_string(), message: e.to_string(),
path: None, path: None,
}], }],
}); }));
} }
}; };
@ -138,107 +139,74 @@ pub async fn enroll(
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(e) => { Err(e) => {
error!("error generating configuration: {}", e); error!("error generating configuration: {}", e);
return HttpResponse::InternalServerError().json(EnrollResponse::Error { return Ok(HttpResponse::InternalServerError().json(EnrollResponse::Error {
errors: vec![APIError { errors: vec![APIError {
code: "ERR_CFG_GENERATION_ERROR".to_string(), code: "ERR_CFG_GENERATION_ERROR".to_string(),
message: "There was an error generating the host configuration.".to_string(), message: "There was an error generating the host configuration.".to_string(),
path: None, path: None,
}], }],
}); }));
} }
}; };
let mut ks_clone = match keystore_init() { // delete all entries in the keystore for this host
Ok(ks) => ks,
Err(e) => {
error!("error loading keystore: {}", e);
return HttpResponse::InternalServerError().json(EnrollResponse::Error {
errors: vec![APIError {
code: "ERR_KS_LOAD_ERROR".to_string(),
message: "There was an error loading the keystore.".to_string(),
path: None,
}],
});
}
};
loop { let entries = keystore_entry::Entity::find().filter(keystore_entry::Column::Host.eq(&enroll_info.host)).all(&db.conn).await?;
let host_in_ks = ks_clone.hosts.iter().position(|u| u.id == enroll_info.host);
if let Some(host) = host_in_ks { for entry in entries {
ks_clone.hosts.remove(host); entry.delete(&db.conn).await?;
} else {
break;
}
} }
let dh_pubkey_typed: [u8; 32] = dh_pubkey.clone().try_into().unwrap(); let host_info = keystore_host::Entity::find().filter(keystore_host::Column::Id.eq(&enroll_info.host)).one(&db.conn).await?;
let host = KeystoreHostInformation { if let Some(old_host) = host_info {
id: enroll_info.host.clone(), old_host.delete(&db.conn).await?;
current_signing_key: 0, }
current_client_key: 1,
current_config: 1,
current_cert: 1,
certs: vec![KSCert { id: 1, cert }],
config: vec![KSConfig {
id: 1,
config: cfg.clone(),
}],
signing_keys: vec![KSSigningKey {
id: 0,
key: SigningKey::generate(&mut OsRng),
}],
client_keys: vec![KSClientKey {
id: 1,
dh_pub: PublicKey::from(dh_pubkey_typed),
ed_pub: VerifyingKey::from_bytes(&ed_pubkey.try_into().unwrap()).unwrap(),
}],
};
ks_clone.hosts.push(host.clone()); let cfg = match serde_yaml::to_string(&cfg) {
Ok(cfg) => cfg,
match keystore_flush(&ks_clone) {
Ok(_) => (),
Err(e) => { Err(e) => {
error!("keystore save error: {}", e); error!("serialization error: {}", e);
return HttpResponse::InternalServerError().json(vec![APIError { return Ok(HttpResponse::BadRequest().json(vec![APIError {
code: "ERR_SAVE_ERR".to_string(), code: "ERR_ED_INVALID".to_string(),
message: "There was an error saving the keystore.".to_string(), message: "There was an error deserializing the ED pubkey.".to_string(),
path: None, path: None,
}]); }]));
} }
} };
HttpResponse::Ok().json(EnrollResponse::Success { let cert_bytes = cert.serialize_to_pem().unwrap();
let key = SigningKey::generate(&mut OsRng);
let host_header = keystore_host::Model {
id: enroll_info.host.clone(),
counter: 1
};
let entry = keystore_entry::Model {
id: random_id("ksentry"),
host: enroll_info.host.clone(),
counter: 1,
certificate: cert_bytes,
client_dh_key: dh_pubkey,
client_signing_key: ed_pubkey,
config: cfg.clone(),
signing_key: key.to_bytes().to_vec()
};
host_header.into_active_model().insert(&db.conn).await?;
entry.into_active_model().insert(&db.conn).await?;
Ok(HttpResponse::Ok().json(EnrollResponse::Success {
data: EnrollResponseData { data: EnrollResponseData {
config: match serde_yaml::to_string(&cfg) { config: cfg.as_bytes().to_vec(),
Ok(cfg) => cfg.as_bytes().to_vec(),
Err(e) => {
error!("serialization error: {}", e);
return HttpResponse::BadRequest().json(vec![APIError {
code: "ERR_ED_INVALID".to_string(),
message: "There was an error deserializing the ED pubkey.".to_string(),
path: None,
}]);
}
},
host_id: enroll_info.host.clone(), host_id: enroll_info.host.clone(),
counter: host.current_config as u32, counter: 1,
trusted_keys: serialize_ed25519_public( trusted_keys: serialize_ed25519_public(&key.verifying_key().to_bytes().to_vec()),
host.signing_keys
.iter()
.find(|u| u.id == host.current_signing_key)
.unwrap()
.key
.verifying_key()
.as_bytes()
.as_slice(),
)
.to_vec(),
organization: EnrollResponseDataOrg { organization: EnrollResponseDataOrg {
id: info.organization.id.clone(), id: info.organization.id.clone(),
name: info.organization.name.clone(), name: info.organization.name.clone(),
}, },
}, },
}) }))
} }