secured_vam_sender_receiver/
secured_vam_sender_receiver.rs1use std::env;
36use std::fs;
37use std::path::Path;
38use std::sync::{mpsc, Arc, Mutex};
39use std::thread;
40use std::time::Duration;
41
42use rustflexstack::btp::router::Router as BTPRouter;
43use rustflexstack::facilities::location_service::{GpsFix, LocationService};
44use rustflexstack::facilities::vru_awareness_service::{DeviceData, VruAwarenessService};
45use rustflexstack::geonet::basic_header::{BasicHeader, BasicNH};
46use rustflexstack::geonet::gn_address::{GNAddress, M, MID, ST};
47use rustflexstack::geonet::mib::Mib;
48use rustflexstack::geonet::position_vector::LongPositionVector;
49use rustflexstack::geonet::router::Router as GNRouter;
50use rustflexstack::link_layer::raw_link_layer::RawLinkLayer;
51
52use rustflexstack::security::certificate::{Certificate, OwnCertificate};
53use rustflexstack::security::certificate_library::CertificateLibrary;
54use rustflexstack::security::ecdsa_backend::EcdsaBackend;
55use rustflexstack::security::sign_service::SignService;
56use rustflexstack::security::sn_sap::{ReportVerify, SNSignRequest, SNVerifyRequest};
57use rustflexstack::security::verify_service::{verify_message, VerifyEvent};
58
59const ITS_AID_VAM: u64 = 638;
60
61fn build_security_stack(at_index: usize) -> SignService {
64 let cert_dir = Path::new("certs");
65
66 let root_bytes = fs::read(cert_dir.join("root_ca.cert"))
68 .expect("root_ca.cert not found — run generate_certificate_chain first");
69 let aa_bytes = fs::read(cert_dir.join("aa.cert"))
70 .expect("aa.cert not found — run generate_certificate_chain first");
71
72 let root_ca = Certificate::from_bytes(&root_bytes, None);
73 let aa = Certificate::from_bytes(&aa_bytes, Some(root_ca.clone()));
74
75 let at1_cert_bytes = fs::read(cert_dir.join("at1.cert")).expect("at1.cert not found");
77 let at2_cert_bytes = fs::read(cert_dir.join("at2.cert")).expect("at2.cert not found");
78
79 let at1 = Certificate::from_bytes(&at1_cert_bytes, Some(aa.clone()));
80 let at2 = Certificate::from_bytes(&at2_cert_bytes, Some(aa.clone()));
81
82 let own_key_file = if at_index == 1 { "at1.key" } else { "at2.key" };
84 let key_bytes = fs::read(cert_dir.join(own_key_file))
85 .unwrap_or_else(|_| panic!("{} not found", own_key_file));
86
87 let mut backend = EcdsaBackend::new();
89 let key_id = backend.import_signing_key(&key_bytes);
90
91 let own_cert = if at_index == 1 {
92 at1.clone()
93 } else {
94 at2.clone()
95 };
96 let peer_cert = if at_index == 1 {
97 at2.clone()
98 } else {
99 at1.clone()
100 };
101
102 let cert_library = CertificateLibrary::new(
104 &backend,
105 vec![root_ca],
106 vec![aa],
107 vec![own_cert.clone(), peer_cert],
108 );
109
110 let mut sign_service = SignService::new(backend, cert_library);
112 let own = OwnCertificate::new(own_cert, key_id);
113 sign_service.add_own_certificate(own);
114
115 sign_service
116}
117
118fn main() {
119 let args: Vec<String> = env::args().collect();
121 let mut at_index: usize = 1;
122 let mut iface = "lo".to_string();
123
124 let mut i = 1;
125 while i < args.len() {
126 match args[i].as_str() {
127 "--at" => {
128 i += 1;
129 at_index = args[i].parse::<usize>().expect("--at must be 1 or 2");
130 assert!(at_index == 1 || at_index == 2, "--at must be 1 or 2");
131 }
132 "--iface" | "-i" => {
133 i += 1;
134 iface = args[i].clone();
135 }
136 other => {
137 iface = other.to_string();
139 }
140 }
141 i += 1;
142 }
143
144 println!("=== Secured VAM Sender/Receiver (VRU Awareness Service) ===");
145 println!("AT index: {}", at_index);
146 println!("Interface: {}", iface);
147
148 let sign_service = build_security_stack(at_index);
150 println!(
151 "Security stack loaded. Own AT HashedId8: {:02x?}",
152 sign_service
153 .cert_library
154 .own_certificates
155 .keys()
156 .next()
157 .unwrap()
158 );
159
160 let sign_service = Arc::new(Mutex::new(sign_service));
162
163 let mac = {
165 use std::time::{SystemTime, UNIX_EPOCH};
166 let seed = SystemTime::now()
167 .duration_since(UNIX_EPOCH)
168 .unwrap()
169 .subsec_nanos()
170 ^ (at_index as u32 * 0x1234_5678); [
172 0x02u8,
173 (seed >> 24) as u8,
174 (seed >> 16) as u8,
175 (seed >> 8) as u8,
176 seed as u8,
177 at_index as u8,
178 ]
179 };
180 println!(
181 "MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
182 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
183 );
184
185 let mut mib = Mib::new();
187 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::Cyclist, MID::new(mac));
188 mib.itsGnBeaconServiceRetransmitTimer = 0;
189
190 let mut loc_svc = LocationService::new();
192 let gn_gps_rx = loc_svc.subscribe();
193 let vru_gps_rx = loc_svc.subscribe();
194
195 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
197 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
198
199 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
201
202 let (secured_ll_tx, secured_ll_rx) = mpsc::channel::<Vec<u8>>();
208 let sign_svc_tx = Arc::clone(&sign_service);
209 thread::spawn(move || {
210 while let Ok(packet) = gn_to_ll_rx.recv() {
211 if packet.len() < 4 {
212 let _ = secured_ll_tx.send(packet);
213 continue;
214 }
215 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
216 let bh = BasicHeader::decode(bh_bytes);
217
218 match bh.nh {
219 BasicNH::CommonHeader if packet.len() > 4 => {
220 let inner_payload = &packet[4..];
221
222 let request = SNSignRequest {
223 tbs_message: inner_payload.to_vec(),
224 its_aid: ITS_AID_VAM,
225 permissions: vec![],
226 generation_location: None,
227 };
228
229 let sec_message = {
230 let mut svc = sign_svc_tx.lock().unwrap();
231 svc.sign_request(&request).sec_message
232 };
233
234 let mut new_bh = bh;
236 new_bh.nh = BasicNH::SecuredPacket;
237 let secured_packet: Vec<u8> = new_bh
238 .encode()
239 .iter()
240 .copied()
241 .chain(sec_message.iter().copied())
242 .collect();
243 let _ = secured_ll_tx.send(secured_packet);
244 }
245 _ => {
246 let _ = secured_ll_tx.send(packet);
248 }
249 }
250 }
251 });
252
253 let raw_ll = RawLinkLayer::new(ll_to_gn_tx, secured_ll_rx, &iface, mac);
255 raw_ll.start();
256
257 let gn_h_rx = gn_handle.clone();
263 let sign_svc_rx = Arc::clone(&sign_service);
264 thread::spawn(move || {
265 while let Ok(packet) = ll_to_gn_rx.recv() {
266 if packet.len() < 4 {
267 gn_h_rx.send_incoming_packet(packet);
268 continue;
269 }
270 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
271 let bh = BasicHeader::decode(bh_bytes);
272
273 match bh.nh {
274 BasicNH::SecuredPacket if packet.len() > 4 => {
275 let sec_message = &packet[4..];
276 let request = SNVerifyRequest {
277 message: sec_message.to_vec(),
278 };
279
280 let (confirm, _events) = {
281 let mut svc = sign_svc_rx.lock().unwrap();
282 let svc = &mut *svc;
283 let result = verify_message(&request, &svc.backend, &mut svc.cert_library);
284 for event in &result.1 {
286 match event {
287 VerifyEvent::UnknownAt(h8) => {
288 svc.notify_unknown_at(h8);
289 }
290 VerifyEvent::InlineP2pcdRequest(h3s) => {
291 svc.notify_inline_p2pcd_request(h3s);
292 }
293 VerifyEvent::ReceivedCaCertificate(cert) => {
294 svc.notify_received_ca_certificate(cert.as_ref().clone());
295 }
296 }
297 }
298 result
299 };
300
301 if confirm.report == ReportVerify::Success {
302 println!(
303 "[SEC RX] Verified OK — ITS-AID={}, cert={:02x?}",
304 confirm.its_aid,
305 &confirm.certificate_id[..],
306 );
307 let mut new_bh = bh;
309 new_bh.nh = BasicNH::CommonHeader;
310 let plain_packet: Vec<u8> = new_bh
311 .encode()
312 .iter()
313 .copied()
314 .chain(confirm.plain_message.iter().copied())
315 .collect();
316 gn_h_rx.send_incoming_packet(plain_packet);
317 } else {
318 eprintln!("[SEC RX] Verification failed: {:?}", confirm.report);
319 }
320 }
321 _ => {
322 gn_h_rx.send_incoming_packet(packet);
324 }
325 }
326 }
327 });
328
329 let btp_h1 = btp_handle.clone();
331 thread::spawn(move || {
332 while let Ok(ind) = gn_to_btp_rx.recv() {
333 btp_h1.send_gn_data_indication(ind);
334 }
335 });
336
337 let gn_h2 = gn_handle.clone();
339 thread::spawn(move || {
340 while let Ok(req) = btp_to_gn_rx.recv() {
341 gn_h2.send_gn_data_request(req);
342 }
343 });
344
345 let gn_h3 = gn_handle.clone();
347 thread::spawn(move || {
348 while let Ok(fix) = gn_gps_rx.recv() {
349 let mut epv = LongPositionVector::decode([0u8; 24]);
350 epv.update_from_gps(
351 fix.latitude,
352 fix.longitude,
353 fix.speed_mps,
354 fix.heading_deg,
355 fix.pai,
356 );
357 gn_h3.update_position_vector(epv);
358 }
359 });
360
361 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
363 let device_data = DeviceData {
364 station_id,
365 station_type: 2, };
367
368 let (vru_svc, vam_rx) = VruAwarenessService::new(btp_handle.clone(), device_data);
369 vru_svc.start(vru_gps_rx);
370
371 thread::spawn(move || {
373 while let Ok(vam) = vam_rx.recv() {
374 let lat = vam
375 .vam
376 .vam_parameters
377 .basic_container
378 .reference_position
379 .latitude
380 .0 as f64
381 / 1e7;
382 let lon = vam
383 .vam
384 .vam_parameters
385 .basic_container
386 .reference_position
387 .longitude
388 .0 as f64
389 / 1e7;
390 println!(
391 "[VAM RX] station={:>10} lat={:.5} lon={:.5}",
392 vam.header.0.station_id.0, lat, lon,
393 );
394 }
395 });
396
397 thread::sleep(Duration::from_millis(100));
399 println!("Publishing GPS fixes @ 10 Hz — Ctrl+C to stop\n");
400
401 loop {
402 thread::sleep(Duration::from_millis(100));
403 loc_svc.publish(GpsFix {
405 latitude: 41.552,
406 longitude: 2.134,
407 altitude_m: 120.0,
408 speed_mps: 1.5,
409 heading_deg: 90.0,
410 pai: true,
411 });
412 }
413}