add session registration with signature checking
This commit is contained in:
Generated
+21
-3
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.3.1"
|
||||
@@ -350,6 +356,7 @@ dependencies = [
|
||||
"esp-radio",
|
||||
"esp-rtos",
|
||||
"esp-storage",
|
||||
"hashbrown",
|
||||
"log",
|
||||
"nb 1.1.0",
|
||||
"rand_core 0.6.4",
|
||||
@@ -664,7 +671,7 @@ version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "641e43d6a60244429117ef2fa7a47182120c7561336ea01f6fb08d634f46bae1"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"allocator-api2 0.3.1",
|
||||
"cfg-if",
|
||||
"document-features",
|
||||
"enumset",
|
||||
@@ -838,7 +845,7 @@ version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "684c4de2f8907b73c9b891fbda65286a86d34fced4b856f36a7896c211f2f265"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"allocator-api2 0.3.1",
|
||||
"bt-hci",
|
||||
"cfg-if",
|
||||
"document-features",
|
||||
@@ -901,7 +908,7 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "162ec711c8d06e79c67b75d01595539e86b0aac209643af98ca87a12250428b3"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"allocator-api2 0.3.1",
|
||||
"cfg-if",
|
||||
"document-features",
|
||||
"embassy-executor",
|
||||
@@ -1041,6 +1048,12 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||
|
||||
[[package]]
|
||||
name = "fugit"
|
||||
version = "0.3.9"
|
||||
@@ -1120,6 +1133,11 @@ name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"allocator-api2 0.2.21",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
|
||||
+26
-3
@@ -9,6 +9,14 @@ import select
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
import os
|
||||
import struct
|
||||
import secrets
|
||||
import nacl
|
||||
import nacl.hash
|
||||
from nacl.encoding import RawEncoder
|
||||
|
||||
from nacl.signing import SigningKey
|
||||
|
||||
from zeroconf import ServiceBrowser, ServiceListener, Zeroconf
|
||||
|
||||
class ZListener(ServiceListener):
|
||||
@@ -31,9 +39,10 @@ class ZListener(ServiceListener):
|
||||
|
||||
|
||||
class Client():
|
||||
def __init__(self):
|
||||
def __init__(self, private_key):
|
||||
self.selected_service_name = None
|
||||
self.bytes_recorded = 0
|
||||
self.private_key = private_key
|
||||
|
||||
self.started = False
|
||||
self.host_addresses = {}
|
||||
@@ -67,7 +76,7 @@ class Client():
|
||||
with open(self.output_pathname(), "wb") as outf:
|
||||
while self.started:
|
||||
print("sending subscribe")
|
||||
b = bytes([interval >> 8, interval & 0xff, 0x54, 0x11, 0, 25] )
|
||||
b = self.session_key + bytes([interval >> 8, interval & 0xff, 0x54, 0x11, 0, 25] )
|
||||
sock.send(b)
|
||||
timeout = time.time() + 60
|
||||
while self.started and time.time() < timeout:
|
||||
@@ -86,8 +95,20 @@ class Client():
|
||||
self.selected_service_name = name
|
||||
self.on_services_changed()
|
||||
|
||||
def register_session(self):
|
||||
session_key = secrets.token_bytes(32)
|
||||
sock = socket.create_connection(self.host_addresses[self.selected_service_name])
|
||||
sig = signing_key.sign(session_key, encoder=RawEncoder)
|
||||
|
||||
sock.send(b"KEY0" + session_key + sig.signature)
|
||||
response = sock.recv(200)
|
||||
print(response.decode(errors="replace"))
|
||||
sock.close()
|
||||
return session_key
|
||||
|
||||
def start_recording(self):
|
||||
if self.selected_service_name != None:
|
||||
self.session_key = self.register_session()
|
||||
self.started = True
|
||||
print("starting record")
|
||||
peer_thread = threading.Thread(target=self.recording_thread_main, daemon = True)
|
||||
@@ -108,6 +129,8 @@ class Client():
|
||||
|
||||
if __name__ == '__main__':
|
||||
import pprint
|
||||
with open("privkey.bin", "rb") as f:
|
||||
signing_key = SigningKey(f.read(), encoder=RawEncoder)
|
||||
|
||||
exists = False
|
||||
|
||||
@@ -123,7 +146,7 @@ if __name__ == '__main__':
|
||||
if self.host_addresses.get(fqname, False):
|
||||
print(f"found {fqname}")
|
||||
|
||||
client = MyClient()
|
||||
client = MyClient(signing_key)
|
||||
|
||||
while not exists:
|
||||
time.sleep(2)
|
||||
|
||||
@@ -50,7 +50,7 @@ smoltcp = { version = "0.12.0", default-features = false, features = [
|
||||
|
||||
|
||||
embassy-futures = "0.1.1"
|
||||
embassy-sync = { version = "0.7" }
|
||||
embassy-sync = "0.7"
|
||||
|
||||
static_cell = "2"
|
||||
embassy-net = { version = "0.7.1", features = [
|
||||
@@ -71,3 +71,4 @@ embedded-storage = "0.3.1"
|
||||
ed25519-dalek = { version = "2", default-features = false, features = ["alloc"] }
|
||||
rand_core = "0.6"
|
||||
nb = "1.1.0"
|
||||
hashbrown = "0.16.1"
|
||||
|
||||
@@ -11,7 +11,7 @@ use embedded_io_async::{Read,ReadExactError};
|
||||
use esp_hal::sha;
|
||||
use core::convert::Infallible;
|
||||
|
||||
use log::{warn, info, error};
|
||||
use log::{warn, info};
|
||||
|
||||
const ERASE_BLOCK_BYTES : usize = 4096;
|
||||
const ED25519_SIGNATURE_BYTES : usize = 64;
|
||||
|
||||
@@ -8,9 +8,11 @@ use embassy_futures::select::select;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use log::info;
|
||||
use log::{warn,info};
|
||||
|
||||
use crate::ecu::Ecu;
|
||||
use crate::wifi::SessionStore;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
enum SubscriptionKind {
|
||||
@@ -68,7 +70,7 @@ impl Subscriber {
|
||||
// interval is per subscription: e.g. we want to get the rpm much
|
||||
// more often than the ecm id
|
||||
|
||||
pub async fn loop_udp_thing(stack : Stack<'_>, ecu: &mut Ecu<'_>) {
|
||||
pub async fn loop_udp_thing(stack : Stack<'_>, ecu: &mut Ecu<'_>, sessions: &SessionStore ) {
|
||||
let mut rx_buffer = [0u8; 4096];
|
||||
let mut tx_buffer = [0u8; 4096];
|
||||
let mut rx_meta = [PacketMetadata::EMPTY; 512];
|
||||
@@ -96,13 +98,20 @@ pub async fn loop_udp_thing(stack : Stack<'_>, ecu: &mut Ecu<'_>) {
|
||||
if let Ok((n, meta)) = res {
|
||||
info!("packet from {:?}", meta.endpoint);
|
||||
|
||||
let mut s = Subscriber {
|
||||
subscriptions: Vec::from([]),
|
||||
endpoint: meta.endpoint,
|
||||
until: Instant::now() + Duration::from_secs(60),
|
||||
};
|
||||
s.update_subscriptions(&buf[0..n]);
|
||||
subscriber = Some(s);
|
||||
if sessions.is_registered(&buf[..32]).await {
|
||||
let mut s = Subscriber {
|
||||
subscriptions: Vec::from([]),
|
||||
endpoint: meta.endpoint,
|
||||
until: Instant::now() + Duration::from_secs(60),
|
||||
};
|
||||
|
||||
s.update_subscriptions(&buf[32..n]);
|
||||
subscriber = Some(s);
|
||||
} else {
|
||||
warn!("subscription attempt without registered session {:?}",
|
||||
&buf[..32]);
|
||||
subscriber = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref mut sub) = subscriber {
|
||||
|
||||
+59
-11
@@ -7,6 +7,9 @@ use alloc::vec::Vec;
|
||||
use alloc::string::String;
|
||||
use alloc::format;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use ed25519_dalek::{VerifyingKey, Verifier, Signature};
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_net::{
|
||||
@@ -14,8 +17,10 @@ use embassy_net::{
|
||||
StackResources
|
||||
};
|
||||
use embassy_futures::join::join3;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::{Duration, Timer, Instant};
|
||||
use esp_alloc as _;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
@@ -89,6 +94,43 @@ fn dns_records(my_ip_address: [u8;4], serial: Option<usize>) -> Vec<mdns::Resour
|
||||
Vec::from(records)
|
||||
}
|
||||
|
||||
pub struct SessionStore {
|
||||
map : Mutex<CriticalSectionRawMutex, HashMap<[u8; 32], Instant>>,
|
||||
public_key: VerifyingKey
|
||||
}
|
||||
|
||||
impl SessionStore {
|
||||
pub fn new() -> Self {
|
||||
let m = HashMap::new();
|
||||
let verifying_key_bytes = include_bytes!("../../pubkey.bin");
|
||||
let public_key: VerifyingKey = VerifyingKey::from_bytes(verifying_key_bytes).expect("verify");
|
||||
|
||||
Self { map : Mutex::new(m), public_key }
|
||||
}
|
||||
|
||||
pub async fn register(&self, key: &[u8], signature: &[u8]) -> bool {
|
||||
info!("pretending to register {:?}", key);
|
||||
|
||||
if self.public_key.verify(key, &Signature::try_from(signature).expect("64 bytes")).is_ok() {
|
||||
let mut m = self.map.lock().await;
|
||||
m.insert(key.try_into().unwrap(), Instant::now() + Duration::from_secs(86400));
|
||||
true
|
||||
} else {
|
||||
warn!("wrong key");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn is_registered(&self, key: &[u8]) -> bool {
|
||||
let m = self.map.lock().await;
|
||||
match m.get(key) {
|
||||
Some(expiry) => *expiry > Instant::now(),
|
||||
None => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn start_wifi(spawner: &Spawner,
|
||||
flasher: crate::ota::Flasher<'_>,
|
||||
wifi_peripheral: esp_hal::peripherals::WIFI<'static>,
|
||||
@@ -140,9 +182,13 @@ pub async fn start_wifi(spawner: &Spawner,
|
||||
|
||||
let mut serial = None;
|
||||
|
||||
|
||||
|
||||
let session_store = SessionStore::new();
|
||||
|
||||
join3(
|
||||
crate::streamer::loop_udp_thing(stack, ecu),
|
||||
run_tcp_handler(stack, flasher),
|
||||
crate::streamer::loop_udp_thing(stack, ecu, &session_store),
|
||||
run_tcp_handler(stack, &session_store, flasher),
|
||||
async {
|
||||
loop {
|
||||
let mdns_thread = mdns::responder(
|
||||
@@ -213,13 +259,8 @@ async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
|
||||
}
|
||||
|
||||
|
||||
fn register_session_key(key : &[u8]) {
|
||||
info!("got session key{:?}", key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
async fn run_tcp_handler(stack : Stack<'_>,
|
||||
sessions : &SessionStore,
|
||||
mut flasher : crate::ota::Flasher<'_>) {
|
||||
let mut rx_buffer = [0; 4096];
|
||||
let mut tx_buffer = [0; 4096];
|
||||
@@ -248,8 +289,15 @@ async fn run_tcp_handler(stack : Stack<'_>,
|
||||
b"KEY0" => {
|
||||
info!("sessionkey");
|
||||
if let Ok(_) = socket.read_exact(&mut buf).await {
|
||||
let (_sig, key) = buf.split_at(64);
|
||||
register_session_key(&key);
|
||||
let (key, sig) = buf.split_at(32);
|
||||
if sessions.register(key, sig).await {
|
||||
info!("registered? {}", sessions.is_registered(key).await);
|
||||
info!("write {:?}", socket.write(b"BYE\n").await);
|
||||
let _ = socket.flush().await;
|
||||
} else {
|
||||
warn!("couldn't register key")
|
||||
}
|
||||
socket.close();
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
|
||||
@@ -141,6 +141,7 @@ X as PoC, add the signed thing into the rust binary and verify the signature at
|
||||
X verify signature before flashing
|
||||
- maintain a hash of session keys for udp listener and expire them eventually
|
||||
- update the subscription request parsing to expect a session key, validate it
|
||||
- udp client needs to send the key
|
||||
- wifi provisioning over ble
|
||||
- add the 12v->5v buck converter, make a cable to plug into diag port
|
||||
- ride
|
||||
|
||||
Reference in New Issue
Block a user