Integrate agent
This commit is contained in:
25
Cargo.lock
generated
25
Cargo.lock
generated
@@ -26,6 +26,16 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agent_lib"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitea.rixxc.de/rixxc/agent_lib.git#2ed3949ee12bebca2d19ec788688cc59e5378ded"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
"shared_memory_heap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
@@ -35,6 +45,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
|
||||
|
||||
[[package]]
|
||||
name = "arraydeque"
|
||||
version = "0.4.5"
|
||||
@@ -975,6 +991,14 @@ dependencies = [
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared_memory_heap"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitea.rixxc.de/rixxc/shared_memory_heap.git#18f1a1b9a6f2d29f215cb238e470ca91f9e03bc3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@@ -1368,6 +1392,7 @@ name = "wireguard-rs"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"agent_lib",
|
||||
"arraydeque",
|
||||
"blake2",
|
||||
"byteorder",
|
||||
|
||||
@@ -29,6 +29,7 @@ rand_core = "^0.5"
|
||||
ring = "0.16"
|
||||
spin = "0.7"
|
||||
zerocopy = "0.3"
|
||||
agent_lib = { git = "https://gitea.rixxc.de/rixxc/agent_lib.git" }
|
||||
|
||||
[dependencies.treebitmap]
|
||||
package = "ip_network_table-deps-treebitmap"
|
||||
|
||||
@@ -25,6 +25,10 @@ rustPlatform.buildRustPackage
|
||||
|
||||
cargoLock = {
|
||||
lockFile = ./Cargo.lock;
|
||||
outputHashes = {
|
||||
"agent_lib-0.1.0" = "sha256-G9PCNDLaJ18pXjoKmdSFOYFT81VJ9GxapOi7EFZMTks=";
|
||||
"shared_memory_heap-0.1.0" = "sha256-AH+wfAMw5z3lND44feQ11VzoVdaqSGnkvTeIQOFlfXQ=";
|
||||
};
|
||||
};
|
||||
|
||||
doCheck = false;
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use agent_lib::X25519PrivKey;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
|
||||
use super::udp::Owner;
|
||||
@@ -78,7 +79,7 @@ pub trait Configuration {
|
||||
/// # Returns
|
||||
///
|
||||
/// The private if set, otherwise None.
|
||||
fn get_private_key(&self) -> Option<StaticSecret>;
|
||||
fn get_private_key(&self) -> Option<X25519PrivKey>;
|
||||
|
||||
/// Returns the protocol version of the device
|
||||
///
|
||||
@@ -240,13 +241,14 @@ impl<T: tun::Tun, B: udp::PlatformUDP> Configuration for WireGuardConfig<T, B> {
|
||||
self.lock().fwmark
|
||||
}
|
||||
|
||||
fn set_private_key(&self, sk: Option<StaticSecret>) {
|
||||
log::info!("configuration, set private key");
|
||||
self.lock().wireguard.set_key(sk)
|
||||
fn set_private_key(&self, _sk: Option<StaticSecret>) {
|
||||
// log::info!("configuration, set private key");
|
||||
// self.lock().wireguard.set_key(sk)
|
||||
}
|
||||
|
||||
fn get_private_key(&self) -> Option<StaticSecret> {
|
||||
self.lock().wireguard.get_sk()
|
||||
fn get_private_key(&self) -> Option<X25519PrivKey> {
|
||||
// self.lock().wireguard.get_sk()
|
||||
Some(X25519PrivKey::from(&[0; 8]))
|
||||
}
|
||||
|
||||
fn get_protocol_version(&self) -> usize {
|
||||
|
||||
@@ -16,7 +16,7 @@ pub fn serialize<C: Configuration, W: io::Write>(writer: &mut W, config: &C) ->
|
||||
// serialize interface
|
||||
config
|
||||
.get_private_key()
|
||||
.map(|sk| write("private_key", hex::encode(sk.to_bytes())));
|
||||
.map(|_sk| write("private_key", hex::encode([0; 32])));
|
||||
|
||||
config
|
||||
.get_listen_port()
|
||||
|
||||
@@ -3,6 +3,9 @@ use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use agent_lib::x22519_pubkey;
|
||||
use agent_lib::X25519PrivKey;
|
||||
use agent_lib::X25519PubKey;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use dashmap::mapref::entry::Entry;
|
||||
use dashmap::DashMap;
|
||||
@@ -14,7 +17,6 @@ use rand_core::{CryptoRng, RngCore};
|
||||
use clear_on_drop::clear::Clear;
|
||||
|
||||
use x25519_dalek::PublicKey;
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
use super::macs;
|
||||
use super::messages::{CookieReply, Initiation, Response};
|
||||
@@ -27,9 +29,9 @@ use super::types::*;
|
||||
const MAX_PEER_PER_DEVICE: usize = 1 << 20;
|
||||
|
||||
pub struct KeyState {
|
||||
pub(super) sk: StaticSecret, // static secret key
|
||||
pub(super) pk: PublicKey, // static public key
|
||||
macs: macs::Validator, // validator for the mac fields
|
||||
pub(super) sk: X25519PrivKey, // static secret key
|
||||
pub(super) pk: X25519PubKey, // static public key
|
||||
macs: macs::Validator, // validator for the mac fields
|
||||
}
|
||||
|
||||
/// The device is generic over an "opaque" type
|
||||
@@ -95,25 +97,31 @@ impl<O> Device<O> {
|
||||
impl<O> Device<O> {
|
||||
/// Initialize a new handshake state machine
|
||||
pub fn new() -> Device<O> {
|
||||
let sk = X25519PrivKey::from(&[0; 8]);
|
||||
let pk = x22519_pubkey(&sk);
|
||||
let macs = {
|
||||
let pk = PublicKey::from(*pk);
|
||||
macs::Validator::new(pk)
|
||||
};
|
||||
Device {
|
||||
keyst: None,
|
||||
keyst: Some(KeyState { sk, pk, macs }),
|
||||
id_map: DashMap::new(),
|
||||
pk_map: HashMap::new(),
|
||||
limiter: Mutex::new(RateLimiter::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_ss(&mut self) -> (Vec<u32>, Option<PublicKey>) {
|
||||
fn update_ss(&mut self) -> (Vec<u32>, Option<X25519PubKey>) {
|
||||
let mut same = None;
|
||||
let mut ids = Vec::with_capacity(self.pk_map.len());
|
||||
for (pk, peer) in self.pk_map.iter_mut() {
|
||||
if let Some(key) = self.keyst.as_ref() {
|
||||
if key.pk.as_bytes() == pk {
|
||||
same = Some(PublicKey::from(*pk));
|
||||
same = Some(X25519PubKey::from(pk));
|
||||
peer.ss.clear()
|
||||
} else {
|
||||
let pk = PublicKey::from(*pk);
|
||||
peer.ss = *key.sk.diffie_hellman(&pk).as_bytes();
|
||||
let pk = X25519PubKey::from(pk);
|
||||
peer.ss = *noise::shared_secret_agent(&key.sk, &pk);
|
||||
}
|
||||
} else {
|
||||
peer.ss.clear();
|
||||
@@ -126,44 +134,6 @@ impl<O> Device<O> {
|
||||
(ids, same)
|
||||
}
|
||||
|
||||
/// Update the secret key of the device
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `sk` - x25519 scalar representing the local private key
|
||||
pub fn set_sk(&mut self, sk: Option<StaticSecret>) -> Option<PublicKey> {
|
||||
// update secret and public key
|
||||
self.keyst = sk.map(|sk| {
|
||||
let pk = PublicKey::from(&sk);
|
||||
let macs = macs::Validator::new(pk);
|
||||
KeyState { pk, sk, macs }
|
||||
});
|
||||
|
||||
// recalculate / erase the shared secrets for every peer
|
||||
let (ids, same) = self.update_ss();
|
||||
|
||||
// release ids from aborted handshakes
|
||||
for id in ids {
|
||||
self.release(id)
|
||||
}
|
||||
|
||||
// if we found a peer matching the device public key
|
||||
// remove it and return its value to the caller
|
||||
same.map(|pk| {
|
||||
self.pk_map.remove(pk.as_bytes());
|
||||
pk
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the secret key of the device
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A secret key (x25519 scalar)
|
||||
pub fn get_sk(&self) -> Option<&StaticSecret> {
|
||||
self.keyst.as_ref().map(|key| &key.sk)
|
||||
}
|
||||
|
||||
/// Add a new public key to the state machine
|
||||
/// To remove public keys, you must create a new machine instance
|
||||
///
|
||||
@@ -172,6 +142,7 @@ impl<O> Device<O> {
|
||||
/// * `pk` - The public key to add
|
||||
/// * `identifier` - Associated identifier which can be used to distinguish the peers
|
||||
pub fn add(&mut self, pk: PublicKey, opaque: O) -> Result<(), ConfigError> {
|
||||
let pk = X25519PubKey::from(pk.as_bytes());
|
||||
// ensure less than 2^20 peers
|
||||
if self.pk_map.len() > MAX_PEER_PER_DEVICE {
|
||||
return Err(ConfigError::new("Too many peers for device"));
|
||||
@@ -185,17 +156,12 @@ impl<O> Device<O> {
|
||||
}
|
||||
|
||||
// pre-compute shared secret and add to pk_map
|
||||
self.pk_map.insert(
|
||||
*pk.as_bytes(),
|
||||
Peer::new(
|
||||
pk,
|
||||
self.keyst
|
||||
.as_ref()
|
||||
.map(|key| *key.sk.diffie_hellman(&pk).as_bytes())
|
||||
.unwrap_or([0u8; 32]),
|
||||
opaque,
|
||||
),
|
||||
);
|
||||
let ss = self
|
||||
.keyst
|
||||
.as_ref()
|
||||
.map(|key| *noise::shared_secret_agent(&key.sk, &pk))
|
||||
.unwrap_or([0u8; 32]);
|
||||
self.pk_map.insert(*pk, Peer::new(pk, ss, opaque));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use agent_lib::X25519PubKey;
|
||||
use generic_array::GenericArray;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use spin::RwLock;
|
||||
@@ -119,10 +120,10 @@ impl Generator {
|
||||
/// # Returns
|
||||
///
|
||||
/// A freshly initated generator
|
||||
pub fn new(pk: PublicKey) -> Generator {
|
||||
pub fn new(pk: X25519PubKey) -> Generator {
|
||||
Generator {
|
||||
mac1_key: HASH!(LABEL_MAC1, pk.as_bytes()).into(),
|
||||
cookie_key: HASH!(LABEL_COOKIE, pk.as_bytes()).into(),
|
||||
mac1_key: HASH!(LABEL_MAC1, *pk).into(),
|
||||
cookie_key: HASH!(LABEL_COOKIE, *pk).into(),
|
||||
last_mac1: None,
|
||||
cookie: None,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use agent_lib::{x25519, X25519PrivKey, X25519PubKey, X25519SharedKey};
|
||||
// DH
|
||||
use x25519_dalek::{PublicKey, SharedSecret, StaticSecret};
|
||||
|
||||
@@ -36,7 +37,7 @@ type HMACBlake2s = Hmac<Blake2s>;
|
||||
|
||||
// convenient alias to pass state temporarily into device.rs and back
|
||||
|
||||
type TemporaryState = (u32, PublicKey, GenericArray<u8, U32>, GenericArray<u8, U32>);
|
||||
type TemporaryState = (u32, X25519PubKey, GenericArray<u8, U32>, GenericArray<u8, U32>);
|
||||
|
||||
const SIZE_CK: usize = 32;
|
||||
const SIZE_HS: usize = 32;
|
||||
@@ -227,6 +228,11 @@ fn shared_secret(sk: &StaticSecret, pk: &PublicKey) -> Result<SharedSecret, Hand
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn shared_secret_agent(sk: &X25519PrivKey, pk: &X25519PubKey) -> X25519SharedKey {
|
||||
x25519(sk, pk)
|
||||
}
|
||||
|
||||
pub(super) fn create_initiation<R: RngCore + CryptoRng, O>(
|
||||
rng: &mut R,
|
||||
keyst: &KeyState,
|
||||
@@ -278,7 +284,7 @@ pub(super) fn create_initiation<R: RngCore + CryptoRng, O>(
|
||||
SEAL!(
|
||||
&key,
|
||||
&hs, // ad
|
||||
keyst.pk.as_bytes(), // pt
|
||||
keyst.pk.as_slice(), // pt
|
||||
&mut msg.f_static // ct || tag
|
||||
);
|
||||
|
||||
@@ -328,7 +334,7 @@ pub(super) fn consume_initiation<'a, O>(
|
||||
|
||||
let ck = INITIAL_CK;
|
||||
let hs = INITIAL_HS;
|
||||
let hs = HASH!(&hs, keyst.pk.as_bytes());
|
||||
let hs = HASH!(&hs, *keyst.pk);
|
||||
|
||||
// C := Kdf(C, E_pub)
|
||||
|
||||
@@ -340,8 +346,8 @@ pub(super) fn consume_initiation<'a, O>(
|
||||
|
||||
// (C, k) := Kdf2(C, DH(E_priv, S_pub))
|
||||
|
||||
let eph_r_pk = PublicKey::from(msg.f_ephemeral);
|
||||
let (ck, key) = KDF2!(&ck, shared_secret(&keyst.sk, &eph_r_pk)?.as_bytes());
|
||||
let eph_r_pk = X25519PubKey::from(&msg.f_ephemeral);
|
||||
let (ck, key) = KDF2!(&ck, shared_secret_agent(&keyst.sk, &eph_r_pk).as_slice());
|
||||
|
||||
// msg.static := Aead(k, 0, S_pub, H)
|
||||
|
||||
@@ -440,6 +446,7 @@ pub(super) fn create_response<R: RngCore + CryptoRng, O>(
|
||||
|
||||
// C := Kdf1(C, DH(E_priv, E_pub))
|
||||
|
||||
let eph_r_pk = PublicKey::from(*eph_r_pk);
|
||||
let ck = KDF1!(&ck, shared_secret(&eph_sk, &eph_r_pk)?.as_bytes());
|
||||
|
||||
// C := Kdf1(C, DH(E_priv, S_pub))
|
||||
@@ -526,7 +533,8 @@ pub(super) fn consume_response<'a, O>(
|
||||
|
||||
// C := Kdf1(C, DH(E_priv, S_pub))
|
||||
|
||||
let ck = KDF1!(&ck, shared_secret(&keyst.sk, &eph_r_pk)?.as_bytes());
|
||||
let eph_r_pk = X25519PubKey::from(&msg.f_ephemeral);
|
||||
let ck = KDF1!(&ck, shared_secret_agent(&keyst.sk, &eph_r_pk).as_slice());
|
||||
|
||||
// (C, tau, k) := Kdf3(C, Q)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use agent_lib::X25519PubKey;
|
||||
use spin::Mutex;
|
||||
|
||||
use std::mem;
|
||||
@@ -59,7 +60,7 @@ impl Drop for State {
|
||||
}
|
||||
|
||||
impl<O> Peer<O> {
|
||||
pub fn new(pk: PublicKey, ss: [u8; 32], opaque: O) -> Self {
|
||||
pub fn new(pk: X25519PubKey, ss: [u8; 32], opaque: O) -> Self {
|
||||
Self {
|
||||
opaque,
|
||||
macs: Mutex::new(macs::Generator::new(pk)),
|
||||
|
||||
@@ -183,16 +183,17 @@ impl<T: Tun, B: UDP> WireGuard<T, B> {
|
||||
}
|
||||
|
||||
pub fn set_key(&self, sk: Option<StaticSecret>) {
|
||||
let mut peers = self.peers.write();
|
||||
peers.set_sk(sk);
|
||||
self.router.clear_sending_keys();
|
||||
// let mut peers = self.peers.write();
|
||||
// peers.set_sk(sk);
|
||||
// self.router.clear_sending_keys();
|
||||
}
|
||||
|
||||
pub fn get_sk(&self) -> Option<StaticSecret> {
|
||||
self.peers
|
||||
.read()
|
||||
.get_sk()
|
||||
.map(|sk| StaticSecret::from(sk.to_bytes()))
|
||||
// self.peers
|
||||
// .read()
|
||||
// .get_sk()
|
||||
// .map(|sk| StaticSecret::from(sk.to_bytes()))
|
||||
None
|
||||
}
|
||||
|
||||
pub fn set_psk(&self, pk: PublicKey, psk: [u8; 32]) -> bool {
|
||||
|
||||
9
test.conf
Normal file
9
test.conf
Normal file
@@ -0,0 +1,9 @@
|
||||
# Agent implementation
|
||||
|
||||
[Interface]
|
||||
ListenPort = 31337
|
||||
|
||||
[Peer]
|
||||
PublicKey = hu/U5Dg+tt9z0vfJZgSjPlVXBoi0Ux4ELFhfLnzBWRc=
|
||||
AllowedIPs = 100.64.100.2/32
|
||||
Endpoint = 167.235.26.58:31338
|
||||
11
test2.conf
Normal file
11
test2.conf
Normal file
@@ -0,0 +1,11 @@
|
||||
# Normal implementation
|
||||
|
||||
[Interface]
|
||||
ListenPort = 31338
|
||||
PrivateKey = cAOHZMXEq20N8/keW4lYrkhej3oCFeMV3uJ/3f22eGQ=
|
||||
Address = 100.64.100.2/24
|
||||
|
||||
[Peer]
|
||||
PublicKey = 9z0xORKt5DZJeqc55/6YFljRz3Kv90yPFsIPgHjIkTs=
|
||||
AllowedIPs = 100.64.100.1/32
|
||||
Endpoint = 127.0.0.1:31337
|
||||
Reference in New Issue
Block a user