Add timestamp
This commit is contained in:
parent
ddc838f2f3
commit
7a40908543
57
src/lib.rs
57
src/lib.rs
@ -7,6 +7,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
use std::time;
|
||||||
use tokio::io::{self, AsyncWriteExt};
|
use tokio::io::{self, AsyncWriteExt};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio::sync::watch::{self, Receiver, Sender};
|
use tokio::sync::watch::{self, Receiver, Sender};
|
||||||
@ -16,6 +17,7 @@ use uuid::Uuid;
|
|||||||
pub struct ProxyCommand {
|
pub struct ProxyCommand {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
command: Command,
|
command: Command,
|
||||||
|
timestamp: Option<u64>,
|
||||||
signature: Option<Signature>,
|
signature: Option<Signature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,8 +25,37 @@ impl ProxyCommand {
|
|||||||
fn verify_signature(&self, verifying_key: &Option<VerifyingKey>) -> bool {
|
fn verify_signature(&self, verifying_key: &Option<VerifyingKey>) -> bool {
|
||||||
match (verifying_key, &self.signature) {
|
match (verifying_key, &self.signature) {
|
||||||
(Some(key), Some(signature)) => {
|
(Some(key), Some(signature)) => {
|
||||||
let message = serde_json::to_string(&self.command).unwrap();
|
let mut message = serde_json::to_string(&self.command).unwrap();
|
||||||
key.verify(message.as_bytes(), signature).is_ok()
|
|
||||||
|
let timestamp = if let Some(timestamp) = self.timestamp {
|
||||||
|
message.push_str(×tamp.to_string());
|
||||||
|
time::Duration::from_secs(timestamp)
|
||||||
|
} else {
|
||||||
|
tracing::debug!("timestamp missing while signature is present");
|
||||||
|
return false; // timestamp missing with signature present
|
||||||
|
};
|
||||||
|
|
||||||
|
if !key.verify(message.as_bytes(), signature).is_ok() {
|
||||||
|
tracing::debug!("signature does not match message");
|
||||||
|
return false; // signature doesn't match
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = time::SystemTime::now()
|
||||||
|
.duration_since(time::UNIX_EPOCH)
|
||||||
|
.unwrap();
|
||||||
|
if now > timestamp {
|
||||||
|
// timestamp is older
|
||||||
|
if now - timestamp <= time::Duration::from_secs(60) {
|
||||||
|
// less than a minute old
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
tracing::warn!("command is more than a minute old");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracing::warn!("command is from the future");
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(Some(_), None) => false,
|
(Some(_), None) => false,
|
||||||
(None, _) => true,
|
(None, _) => true,
|
||||||
@ -310,7 +341,10 @@ async fn transfer(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::{
|
||||||
|
net::{IpAddr, Ipv4Addr},
|
||||||
|
time,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{Command, ProxyCommand};
|
use crate::{Command, ProxyCommand};
|
||||||
use p384::{
|
use p384::{
|
||||||
@ -330,10 +364,12 @@ mod tests {
|
|||||||
destination_ip: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
destination_ip: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||||
id: uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"),
|
id: uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"),
|
||||||
},
|
},
|
||||||
|
timestamp: Some(8888),
|
||||||
signature: Some(signature),
|
signature: Some(signature),
|
||||||
};
|
};
|
||||||
let expected = "{\"create\":{\"incoming_port\":5555,\"destination_port\":6666,\"\
|
let expected = "{\"create\":{\"incoming_port\":5555,\"destination_port\":6666,\"\
|
||||||
destination_ip\":\"127.0.0.1\",\"id\":\"67e55044-10b1-426f-9247-bb680e5fe0c8\"},\
|
destination_ip\":\"127.0.0.1\",\"id\":\"67e55044-10b1-426f-9247-bb680e5fe0c8\"},\
|
||||||
|
\"timestamp\":8888,\
|
||||||
\"signature\":\"\
|
\"signature\":\"\
|
||||||
5C912C4B3BFF2ADB49885DCBDB53D6D3041D0632E498CDFF\
|
5C912C4B3BFF2ADB49885DCBDB53D6D3041D0632E498CDFF\
|
||||||
2114CD2DCAC936AB0901B47C411E5BB57FE77BEF96044940\
|
2114CD2DCAC936AB0901B47C411E5BB57FE77BEF96044940\
|
||||||
@ -351,9 +387,11 @@ mod tests {
|
|||||||
command: Command::Delete {
|
command: Command::Delete {
|
||||||
id: uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"),
|
id: uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"),
|
||||||
},
|
},
|
||||||
|
timestamp: Some(987654),
|
||||||
signature: Some(signature),
|
signature: Some(signature),
|
||||||
};
|
};
|
||||||
let expected = "{\"delete\":{\"id\":\"67e55044-10b1-426f-9247-bb680e5fe0c8\"},\
|
let expected = "{\"delete\":{\"id\":\"67e55044-10b1-426f-9247-bb680e5fe0c8\"},\
|
||||||
|
\"timestamp\":987654,\
|
||||||
\"signature\":\"\
|
\"signature\":\"\
|
||||||
5C912C4B3BFF2ADB49885DCBDB53D6D3041D0632E498CDFF\
|
5C912C4B3BFF2ADB49885DCBDB53D6D3041D0632E498CDFF\
|
||||||
2114CD2DCAC936AB0901B47C411E5BB57FE77BEF96044940\
|
2114CD2DCAC936AB0901B47C411E5BB57FE77BEF96044940\
|
||||||
@ -365,6 +403,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_signature() {
|
fn verify_signature() {
|
||||||
|
let subscriber = tracing_subscriber::FmtSubscriber::builder()
|
||||||
|
.with_max_level(tracing::Level::TRACE)
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||||
|
|
||||||
let command = Command::Create {
|
let command = Command::Create {
|
||||||
incoming_port: 4567,
|
incoming_port: 4567,
|
||||||
destination_port: 7654,
|
destination_port: 7654,
|
||||||
@ -374,12 +417,18 @@ mod tests {
|
|||||||
|
|
||||||
// Create signed message
|
// Create signed message
|
||||||
let signing_key = SigningKey::random(&mut OsRng);
|
let signing_key = SigningKey::random(&mut OsRng);
|
||||||
let message = serde_json::to_string(&command).unwrap();
|
let timestamp = time::SystemTime::now()
|
||||||
|
.duration_since(time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs();
|
||||||
|
let mut message = serde_json::to_string(&command).unwrap();
|
||||||
|
message.push_str(×tamp.to_string());
|
||||||
let signature: Signature = signing_key.sign(message.as_bytes());
|
let signature: Signature = signing_key.sign(message.as_bytes());
|
||||||
let bytes = signature.to_bytes();
|
let bytes = signature.to_bytes();
|
||||||
assert_eq!(bytes.len(), 96);
|
assert_eq!(bytes.len(), 96);
|
||||||
let proxy_command = ProxyCommand {
|
let proxy_command = ProxyCommand {
|
||||||
command,
|
command,
|
||||||
|
timestamp: Some(timestamp),
|
||||||
signature: Some(signature),
|
signature: Some(signature),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user