mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2026-11-02 20:30:15 -06:00
PKI for the license server. Replies to public key exchange requests with a server-cluster side public key. 69 bytes, not too heavy.
This commit is contained in:
1 parent
86dabaeded
commit
403dddd1b9
6 files changed
+81
-2
No files matched your search
@@ -54,6 +54,7 @@ src/webusers.toml
|
||||
src/lqusers.toml
|
||||
src/dist
|
||||
src/rust/lqos_anonymous_stats_server/anonymous.sqlite
|
||||
src/rust/long_term_stats/license_server/lqkeys.bin
|
||||
|
||||
# Ignore Rust build artifacts
|
||||
src/rust/target
|
||||
|
||||
Generated
+2
@@ -1604,9 +1604,11 @@ name = "license_server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dryoc",
|
||||
"env_logger",
|
||||
"log",
|
||||
"lqos_bus",
|
||||
"once_cell",
|
||||
"pgdb",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
|
||||
@@ -11,4 +11,6 @@ log = "0"
|
||||
serde_cbor = "0" # For RFC8949/7409 format C binary objects
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
lqos_bus = { path = "../../lqos_bus" }
|
||||
pgdb = { path = "../pgdb" }
|
||||
pgdb = { path = "../pgdb" }
|
||||
dryoc = { version = "0.5", features = ["serde"] }
|
||||
once_cell = "1"
|
||||
@@ -1,4 +1,5 @@
|
||||
mod server;
|
||||
mod pki;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
use std::{sync::RwLock, path::Path};
|
||||
use dryoc::dryocbox::*;
|
||||
use lqos_bus::bincode;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
pub(crate) static LIBREQOS_KEYPAIR: Lazy<RwLock<KeyPair>> = Lazy::new(|| RwLock::new(generate_new_keypair()));
|
||||
const KEY_PATH: &str = "lqkeys.bin"; // Store in the working directory
|
||||
|
||||
pub(crate) fn generate_new_keypair() -> KeyPair {
|
||||
let path = Path::new(KEY_PATH);
|
||||
if path.exists() {
|
||||
if let Ok(bytes) = std::fs::read(path) {
|
||||
if let Ok(keypair) = bincode::deserialize(&bytes) {
|
||||
log::info!("Loaded keypair from {}", path.display());
|
||||
return keypair;
|
||||
}
|
||||
}
|
||||
}
|
||||
let keypair = KeyPair::gen();
|
||||
let bytes = bincode::serialize(&keypair).unwrap();
|
||||
std::fs::write(path, bytes).unwrap();
|
||||
log::info!("Generated new keypair and stored it at {}", path.display());
|
||||
keypair
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use dryoc::dryocbox::*;
|
||||
use lqos_bus::bincode;
|
||||
|
||||
#[test]
|
||||
fn test_sealed_box_roundtrip() {
|
||||
let sender_keypair = KeyPair::gen();
|
||||
let recipient_keypair = KeyPair::gen();
|
||||
let nonce = Nonce::gen();
|
||||
let message = b"Once upon a time, there was a man with a dream.";
|
||||
let dryocbox = DryocBox::encrypt_to_vecbox(
|
||||
message,
|
||||
&nonce,
|
||||
&recipient_keypair.public_key,
|
||||
&sender_keypair.secret_key,
|
||||
)
|
||||
.expect("unable to encrypt");
|
||||
|
||||
let sodium_box = dryocbox.to_vec();
|
||||
let dryocbox = DryocBox::from_bytes(&sodium_box).expect("failed to read box");
|
||||
let decrypted = dryocbox
|
||||
.decrypt_to_vec(
|
||||
&nonce,
|
||||
&sender_keypair.public_key,
|
||||
&recipient_keypair.secret_key,
|
||||
)
|
||||
.expect("unable to decrypt");
|
||||
|
||||
assert_eq!(message, decrypted.as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_keypair() {
|
||||
let keypair = KeyPair::gen();
|
||||
let serialized = bincode::serialize(&keypair).unwrap();
|
||||
let deserialized : KeyPair = bincode::deserialize(&serialized).unwrap();
|
||||
assert_eq!(keypair, deserialized);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ use tokio::{
|
||||
spawn,
|
||||
};
|
||||
|
||||
use crate::pki::LIBREQOS_KEYPAIR;
|
||||
|
||||
pub async fn start() -> anyhow::Result<()> {
|
||||
let listener = TcpListener::bind(":::9126").await?;
|
||||
log::info!("Listening on :::9126");
|
||||
@@ -33,6 +35,7 @@ pub async fn start() -> anyhow::Result<()> {
|
||||
let bytes = build_reply(&reply);
|
||||
match bytes {
|
||||
Ok(bytes) => {
|
||||
log::info!("Submitting {} bytes to network", bytes.len());
|
||||
if let Err(e) = socket.write_all(&bytes).await {
|
||||
log::error!("Write error: {e:?}");
|
||||
}
|
||||
@@ -108,7 +111,12 @@ async fn check_license(
|
||||
}
|
||||
}
|
||||
LicenseRequest::KeyExchange { node_id, license_key, public_key } => {
|
||||
Ok(LicenseReply::Denied)
|
||||
log::info!("Public key exchange requested by {node_id}");
|
||||
|
||||
// TODO: Associate the node & license key with their key
|
||||
|
||||
let public_key = LIBREQOS_KEYPAIR.read().unwrap().public_key.clone();
|
||||
Ok(LicenseReply::MyPublicKey { public_key })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user