1pub mod types;
2pub mod handshake;
3pub mod crypto;
4pub mod keepalive;
5pub mod identify;
6
7use alloc::vec::Vec;
8
9use rns_crypto::ed25519::{Ed25519PrivateKey, Ed25519PublicKey};
10use rns_crypto::token::Token;
11use rns_crypto::x25519::X25519PrivateKey;
12use rns_crypto::Rng;
13
14use crate::constants::{
15 LINK_ECPUBSIZE, LINK_KEEPALIVE_MAX, MTU,
16 LINK_ESTABLISHMENT_TIMEOUT_PER_HOP,
17};
18
19pub use types::{LinkAction, LinkError, LinkId, LinkMode, LinkState, TeardownReason};
20
21use handshake::{
22 build_linkrequest_data, compute_link_id, pack_rtt, parse_linkrequest_data,
23 perform_key_exchange, unpack_rtt, validate_lrproof,
24};
25use crypto::{create_session_token, link_decrypt, link_encrypt};
26use keepalive::{
27 compute_establishment_timeout, compute_keepalive, compute_stale_time,
28 is_establishment_timeout, should_go_stale, should_send_keepalive,
29};
30
31pub struct LinkEngine {
36 link_id: LinkId,
37 state: LinkState,
38 is_initiator: bool,
39 mode: LinkMode,
40
41 prv: X25519PrivateKey,
43
44 peer_pub_bytes: Option<[u8; 32]>,
46 peer_sig_pub_bytes: Option<[u8; 32]>,
47
48 derived_key: Option<Vec<u8>>,
50 token: Option<Token>,
51
52 request_time: f64,
54 activated_at: Option<f64>,
55 last_inbound: f64,
56 last_outbound: f64,
57 last_keepalive: f64,
58 last_proof: f64,
59 rtt: Option<f64>,
60 keepalive_interval: f64,
61 stale_time: f64,
62 establishment_timeout: f64,
63
64 remote_identity: Option<([u8; 16], [u8; 64])>,
66 destination_hash: [u8; 16],
67
68 mtu: u32,
70 mdu: usize,
71}
72
73impl LinkEngine {
74 pub fn new_initiator(
79 dest_hash: &[u8; 16],
80 hops: u8,
81 mode: LinkMode,
82 mtu: Option<u32>,
83 now: f64,
84 rng: &mut dyn Rng,
85 ) -> (Self, Vec<u8>) {
86 let prv = X25519PrivateKey::generate(rng);
87 let pub_bytes = prv.public_key().public_bytes();
88 let sig_prv = Ed25519PrivateKey::generate(rng);
89 let sig_pub_bytes = sig_prv.public_key().public_bytes();
90
91 let request_data = build_linkrequest_data(&pub_bytes, &sig_pub_bytes, mtu, mode);
92
93 let link_mtu = mtu.unwrap_or(MTU as u32);
94
95 let engine = LinkEngine {
96 link_id: [0u8; 16], state: LinkState::Pending,
98 is_initiator: true,
99 mode,
100 prv,
101 peer_pub_bytes: None,
102 peer_sig_pub_bytes: None,
103 derived_key: None,
104 token: None,
105 request_time: now,
106 activated_at: None,
107 last_inbound: now,
108 last_outbound: now,
109 last_keepalive: now,
110 last_proof: 0.0,
111 rtt: None,
112 keepalive_interval: LINK_KEEPALIVE_MAX,
113 stale_time: LINK_KEEPALIVE_MAX * 2.0,
114 establishment_timeout: compute_establishment_timeout(
115 LINK_ESTABLISHMENT_TIMEOUT_PER_HOP,
116 hops,
117 ),
118 remote_identity: None,
119 destination_hash: *dest_hash,
120 mtu: link_mtu,
121 mdu: compute_mdu(link_mtu as usize),
122 };
123
124 (engine, request_data)
125 }
126
127 pub fn set_link_id_from_hashable(&mut self, hashable_part: &[u8], data_len: usize) {
132 let extra = if data_len > LINK_ECPUBSIZE {
133 data_len - LINK_ECPUBSIZE
134 } else {
135 0
136 };
137 self.link_id = compute_link_id(hashable_part, extra);
138 }
139
140 pub fn new_responder(
145 owner_sig_prv: &Ed25519PrivateKey,
146 owner_sig_pub_bytes: &[u8; 32],
147 linkrequest_data: &[u8],
148 hashable_part: &[u8],
149 dest_hash: &[u8; 16],
150 hops: u8,
151 now: f64,
152 rng: &mut dyn Rng,
153 ) -> Result<(Self, Vec<u8>), LinkError> {
154 let (peer_pub, peer_sig_pub, peer_mtu, mode) = parse_linkrequest_data(linkrequest_data)?;
155
156 let extra = if linkrequest_data.len() > LINK_ECPUBSIZE {
157 linkrequest_data.len() - LINK_ECPUBSIZE
158 } else {
159 0
160 };
161 let link_id = compute_link_id(hashable_part, extra);
162
163 let prv = X25519PrivateKey::generate(rng);
165 let pub_bytes = prv.public_key().public_bytes();
166 let sig_pub_bytes = *owner_sig_pub_bytes;
167
168 let derived_key = perform_key_exchange(&prv, &peer_pub, &link_id, mode)?;
170 let token = create_session_token(&derived_key)?;
171
172 let link_mtu = peer_mtu.unwrap_or(MTU as u32);
173
174 let lrproof_data = handshake::build_lrproof(
176 &link_id,
177 &pub_bytes,
178 &sig_pub_bytes,
179 owner_sig_prv,
180 peer_mtu,
181 mode,
182 );
183
184 let engine = LinkEngine {
185 link_id,
186 state: LinkState::Handshake,
187 is_initiator: false,
188 mode,
189 prv,
190 peer_pub_bytes: Some(peer_pub),
191 peer_sig_pub_bytes: Some(peer_sig_pub),
192 derived_key: Some(derived_key),
193 token: Some(token),
194 request_time: now,
195 activated_at: None,
196 last_inbound: now,
197 last_outbound: now,
198 last_keepalive: now,
199 last_proof: 0.0,
200 rtt: None,
201 keepalive_interval: LINK_KEEPALIVE_MAX,
202 stale_time: LINK_KEEPALIVE_MAX * 2.0,
203 establishment_timeout: compute_establishment_timeout(
204 LINK_ESTABLISHMENT_TIMEOUT_PER_HOP,
205 hops,
206 ),
207 remote_identity: None,
208 destination_hash: *dest_hash,
209 mtu: link_mtu,
210 mdu: compute_mdu(link_mtu as usize),
211 };
212
213 Ok((engine, lrproof_data))
214 }
215
216 pub fn handle_lrproof(
221 &mut self,
222 proof_data: &[u8],
223 peer_sig_pub_bytes: &[u8; 32],
224 now: f64,
225 rng: &mut dyn Rng,
226 ) -> Result<(Vec<u8>, Vec<LinkAction>), LinkError> {
227 if self.state != LinkState::Pending || !self.is_initiator {
228 return Err(LinkError::InvalidState);
229 }
230
231 let peer_sig_pub = Ed25519PublicKey::from_bytes(peer_sig_pub_bytes);
232
233 let (peer_pub, confirmed_mtu, confirmed_mode) =
234 validate_lrproof(proof_data, &self.link_id, &peer_sig_pub, peer_sig_pub_bytes)?;
235
236 if confirmed_mode != self.mode {
237 return Err(LinkError::UnsupportedMode);
238 }
239
240 self.peer_pub_bytes = Some(peer_pub);
241 self.peer_sig_pub_bytes = Some(*peer_sig_pub_bytes);
242
243 let derived_key = perform_key_exchange(&self.prv, &peer_pub, &self.link_id, self.mode)?;
245 let token = create_session_token(&derived_key)?;
246
247 self.derived_key = Some(derived_key);
248 self.token = Some(token);
249
250 if let Some(mtu) = confirmed_mtu {
252 self.mtu = mtu;
253 self.mdu = compute_mdu(mtu as usize);
254 }
255
256 let rtt = now - self.request_time;
258 self.rtt = Some(rtt);
259 self.state = LinkState::Active;
260 self.activated_at = Some(now);
261 self.last_inbound = now;
262 self.update_keepalive();
263
264 let rtt_packed = pack_rtt(rtt);
266 let rtt_encrypted = self.encrypt(&rtt_packed, rng)?;
267
268 let mut actions = Vec::new();
269 actions.push(LinkAction::StateChanged {
270 link_id: self.link_id,
271 new_state: LinkState::Active,
272 reason: None,
273 });
274 actions.push(LinkAction::LinkEstablished {
275 link_id: self.link_id,
276 rtt,
277 is_initiator: true,
278 });
279
280 Ok((rtt_encrypted, actions))
281 }
282
283 pub fn handle_lrrtt(
287 &mut self,
288 encrypted_data: &[u8],
289 now: f64,
290 ) -> Result<Vec<LinkAction>, LinkError> {
291 if self.state != LinkState::Handshake || self.is_initiator {
292 return Err(LinkError::InvalidState);
293 }
294
295 let plaintext = self.decrypt(encrypted_data)?;
296 let initiator_rtt = unpack_rtt(&plaintext).ok_or(LinkError::InvalidData)?;
297
298 let measured_rtt = now - self.request_time;
299 let rtt = if measured_rtt > initiator_rtt { measured_rtt } else { initiator_rtt };
300
301 self.rtt = Some(rtt);
302 self.state = LinkState::Active;
303 self.activated_at = Some(now);
304 self.last_inbound = now;
305 self.update_keepalive();
306
307 let mut actions = Vec::new();
308 actions.push(LinkAction::StateChanged {
309 link_id: self.link_id,
310 new_state: LinkState::Active,
311 reason: None,
312 });
313 actions.push(LinkAction::LinkEstablished {
314 link_id: self.link_id,
315 rtt,
316 is_initiator: false,
317 });
318
319 Ok(actions)
320 }
321
322 pub fn encrypt(&self, plaintext: &[u8], rng: &mut dyn Rng) -> Result<Vec<u8>, LinkError> {
324 let token = self.token.as_ref().ok_or(LinkError::NoSessionKey)?;
325 Ok(link_encrypt(token, plaintext, rng))
326 }
327
328 pub fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, LinkError> {
330 let token = self.token.as_ref().ok_or(LinkError::NoSessionKey)?;
331 link_decrypt(token, ciphertext)
332 }
333
334 pub fn build_identify(
336 &self,
337 identity: &rns_crypto::identity::Identity,
338 rng: &mut dyn Rng,
339 ) -> Result<Vec<u8>, LinkError> {
340 if self.state != LinkState::Active {
341 return Err(LinkError::InvalidState);
342 }
343 let plaintext = identify::build_identify_data(identity, &self.link_id)?;
344 self.encrypt(&plaintext, rng)
345 }
346
347 pub fn handle_identify(&mut self, encrypted_data: &[u8]) -> Result<Vec<LinkAction>, LinkError> {
351 if self.state != LinkState::Active || self.is_initiator {
352 return Err(LinkError::InvalidState);
353 }
354
355 let plaintext = self.decrypt(encrypted_data)?;
356 let (identity_hash, public_key) = identify::validate_identify_data(&plaintext, &self.link_id)?;
357 self.remote_identity = Some((identity_hash, public_key));
358
359 Ok(alloc::vec![LinkAction::RemoteIdentified {
360 link_id: self.link_id,
361 identity_hash,
362 public_key,
363 }])
364 }
365
366 pub fn record_inbound(&mut self, now: f64) -> Vec<LinkAction> {
370 self.last_inbound = now;
371 if self.state == LinkState::Stale {
372 self.state = LinkState::Active;
373 return alloc::vec![LinkAction::StateChanged {
374 link_id: self.link_id,
375 new_state: LinkState::Active,
376 reason: None,
377 }];
378 }
379 Vec::new()
380 }
381
382 pub fn record_proof(&mut self, now: f64) {
384 self.last_proof = now;
385 }
386
387 pub fn record_outbound(&mut self, now: f64, is_keepalive: bool) {
389 self.last_outbound = now;
390 if is_keepalive {
391 self.last_keepalive = now;
392 }
393 }
394
395 pub fn tick(&mut self, now: f64) -> Vec<LinkAction> {
397 let mut actions = Vec::new();
398
399 match self.state {
400 LinkState::Pending | LinkState::Handshake => {
401 if is_establishment_timeout(self.request_time, self.establishment_timeout, now) {
402 self.state = LinkState::Closed;
403 actions.push(LinkAction::StateChanged {
404 link_id: self.link_id,
405 new_state: LinkState::Closed,
406 reason: Some(TeardownReason::Timeout),
407 });
408 }
409 }
410 LinkState::Active => {
411 let activated = self.activated_at.unwrap_or(0.0);
412 let last_inbound = self.last_inbound.max(self.last_proof).max(activated);
414
415 if should_go_stale(last_inbound, self.stale_time, now) {
416 self.state = LinkState::Stale;
417 actions.push(LinkAction::StateChanged {
418 link_id: self.link_id,
419 new_state: LinkState::Stale,
420 reason: None,
421 });
422 }
423 }
424 LinkState::Stale => {
425 self.state = LinkState::Closed;
427 actions.push(LinkAction::StateChanged {
428 link_id: self.link_id,
429 new_state: LinkState::Closed,
430 reason: Some(TeardownReason::Timeout),
431 });
432 }
433 LinkState::Closed => {}
434 }
435
436 actions
437 }
438
439 pub fn needs_keepalive(&self, now: f64) -> bool {
441 if self.state != LinkState::Active {
442 return false;
443 }
444 let activated = self.activated_at.unwrap_or(0.0);
445 let last_inbound = self.last_inbound.max(self.last_proof).max(activated);
446
447 if now < last_inbound + self.keepalive_interval {
449 return false;
450 }
451
452 should_send_keepalive(self.last_keepalive, self.keepalive_interval, now)
453 }
454
455 pub fn teardown(&mut self) -> Vec<LinkAction> {
457 if self.state == LinkState::Closed {
458 return Vec::new();
459 }
460 self.state = LinkState::Closed;
461 let reason = if self.is_initiator {
462 TeardownReason::InitiatorClosed
463 } else {
464 TeardownReason::DestinationClosed
465 };
466 alloc::vec![LinkAction::StateChanged {
467 link_id: self.link_id,
468 new_state: LinkState::Closed,
469 reason: Some(reason),
470 }]
471 }
472
473 pub fn handle_teardown(&mut self) -> Vec<LinkAction> {
475 if self.state == LinkState::Closed {
476 return Vec::new();
477 }
478 self.state = LinkState::Closed;
479 let reason = if self.is_initiator {
480 TeardownReason::DestinationClosed
481 } else {
482 TeardownReason::InitiatorClosed
483 };
484 alloc::vec![LinkAction::StateChanged {
485 link_id: self.link_id,
486 new_state: LinkState::Closed,
487 reason: Some(reason),
488 }]
489 }
490
491 pub fn link_id(&self) -> &LinkId {
494 &self.link_id
495 }
496
497 pub fn state(&self) -> LinkState {
498 self.state
499 }
500
501 pub fn rtt(&self) -> Option<f64> {
502 self.rtt
503 }
504
505 pub fn mdu(&self) -> usize {
506 self.mdu
507 }
508
509 pub fn is_initiator(&self) -> bool {
510 self.is_initiator
511 }
512
513 pub fn mode(&self) -> LinkMode {
514 self.mode
515 }
516
517 pub fn remote_identity(&self) -> Option<&([u8; 16], [u8; 64])> {
518 self.remote_identity.as_ref()
519 }
520
521 pub fn destination_hash(&self) -> &[u8; 16] {
522 &self.destination_hash
523 }
524
525 pub fn derived_key(&self) -> Option<&[u8]> {
527 self.derived_key.as_deref()
528 }
529
530 pub fn keepalive_interval(&self) -> f64 {
531 self.keepalive_interval
532 }
533
534 pub fn set_rtt(&mut self, rtt: f64) {
537 self.rtt = Some(rtt);
538 self.update_keepalive();
539 }
540
541 pub fn set_mtu(&mut self, mtu: u32) {
543 self.mtu = mtu;
544 self.mdu = compute_mdu(mtu as usize);
545 }
546
547 fn update_keepalive(&mut self) {
550 if let Some(rtt) = self.rtt {
551 self.keepalive_interval = compute_keepalive(rtt);
552 self.stale_time = compute_stale_time(self.keepalive_interval);
553 }
554 }
555}
556
557fn compute_mdu(mtu: usize) -> usize {
561 use crate::constants::{AES128_BLOCKSIZE, HEADER_MINSIZE, IFAC_MIN_SIZE, TOKEN_OVERHEAD};
562 let numerator = mtu.saturating_sub(IFAC_MIN_SIZE + HEADER_MINSIZE + TOKEN_OVERHEAD);
563 (numerator / AES128_BLOCKSIZE) * AES128_BLOCKSIZE - 1
564}
565
566#[cfg(test)]
567mod tests {
568 use super::*;
569 use crate::constants::LINK_MDU;
570 use rns_crypto::FixedRng;
571
572 fn make_rng(seed: u8) -> FixedRng {
573 FixedRng::new(&[seed; 128])
574 }
575
576 #[test]
577 fn test_compute_mdu_default() {
578 assert_eq!(compute_mdu(500), LINK_MDU);
579 }
580
581 #[test]
582 fn test_full_handshake() {
583 let mut rng_id = make_rng(0x01);
585 let dest_sig_prv = Ed25519PrivateKey::generate(&mut rng_id);
586 let dest_sig_pub_bytes = dest_sig_prv.public_key().public_bytes();
587
588 let dest_hash = [0xDD; 16];
589 let mode = LinkMode::Aes256Cbc;
590
591 let mut rng_init = make_rng(0x10);
593 let (mut initiator, request_data) = LinkEngine::new_initiator(
594 &dest_hash, 1, mode, Some(500), 100.0, &mut rng_init,
595 );
596 assert_eq!(initiator.state(), LinkState::Pending);
597
598 let mut hashable = Vec::new();
601 hashable.push(0x00); hashable.push(0x00); hashable.extend_from_slice(&dest_hash);
604 hashable.push(0x00); hashable.extend_from_slice(&request_data);
606
607 initiator.set_link_id_from_hashable(&hashable, request_data.len());
608 assert_ne!(initiator.link_id(), &[0u8; 16]);
609
610 let mut rng_resp = make_rng(0x20);
612 let (mut responder, lrproof_data) = LinkEngine::new_responder(
613 &dest_sig_prv,
614 &dest_sig_pub_bytes,
615 &request_data,
616 &hashable,
617 &dest_hash,
618 1,
619 100.5,
620 &mut rng_resp,
621 ).unwrap();
622 assert_eq!(responder.state(), LinkState::Handshake);
623 assert_eq!(responder.link_id(), initiator.link_id());
624
625 let mut rng_lrrtt = make_rng(0x30);
627 let (lrrtt_encrypted, actions) = initiator.handle_lrproof(
628 &lrproof_data,
629 &dest_sig_pub_bytes,
630 100.8,
631 &mut rng_lrrtt,
632 ).unwrap();
633 assert_eq!(initiator.state(), LinkState::Active);
634 assert!(initiator.rtt().is_some());
635 assert_eq!(actions.len(), 2); let actions = responder.handle_lrrtt(&lrrtt_encrypted, 101.0).unwrap();
639 assert_eq!(responder.state(), LinkState::Active);
640 assert!(responder.rtt().is_some());
641 assert_eq!(actions.len(), 2);
642 }
643
644 #[test]
645 fn test_encrypt_decrypt_after_handshake() {
646 let mut rng_id = make_rng(0x01);
647 let dest_sig_prv = Ed25519PrivateKey::generate(&mut rng_id);
648 let dest_sig_pub_bytes = dest_sig_prv.public_key().public_bytes();
649 let dest_hash = [0xDD; 16];
650
651 let mut rng_init = make_rng(0x10);
652 let (mut initiator, request_data) = LinkEngine::new_initiator(
653 &dest_hash, 1, LinkMode::Aes256Cbc, Some(500), 100.0, &mut rng_init,
654 );
655 let mut hashable = Vec::new();
656 hashable.push(0x00);
657 hashable.push(0x00);
658 hashable.extend_from_slice(&dest_hash);
659 hashable.push(0x00);
660 hashable.extend_from_slice(&request_data);
661 initiator.set_link_id_from_hashable(&hashable, request_data.len());
662
663 let mut rng_resp = make_rng(0x20);
664 let (mut responder, lrproof_data) = LinkEngine::new_responder(
665 &dest_sig_prv, &dest_sig_pub_bytes, &request_data, &hashable,
666 &dest_hash, 1, 100.5, &mut rng_resp,
667 ).unwrap();
668
669 let mut rng_lrrtt = make_rng(0x30);
670 let (lrrtt_encrypted, _) = initiator.handle_lrproof(
671 &lrproof_data, &dest_sig_pub_bytes, 100.8, &mut rng_lrrtt,
672 ).unwrap();
673 responder.handle_lrrtt(&lrrtt_encrypted, 101.0).unwrap();
674
675 let mut rng_enc = make_rng(0x40);
677 let plaintext = b"Hello over encrypted link!";
678 let ciphertext = initiator.encrypt(plaintext, &mut rng_enc).unwrap();
679 let decrypted = responder.decrypt(&ciphertext).unwrap();
680 assert_eq!(decrypted, plaintext);
681
682 let mut rng_enc2 = make_rng(0x50);
684 let ciphertext2 = responder.encrypt(b"Reply!", &mut rng_enc2).unwrap();
685 let decrypted2 = initiator.decrypt(&ciphertext2).unwrap();
686 assert_eq!(decrypted2, b"Reply!");
687 }
688
689 #[test]
690 fn test_tick_establishment_timeout() {
691 let mut rng = make_rng(0x10);
692 let dest_hash = [0xDD; 16];
693 let (mut engine, _) = LinkEngine::new_initiator(
694 &dest_hash, 1, LinkMode::Aes256Cbc, None, 100.0, &mut rng,
695 );
696 let actions = engine.tick(110.0);
700 assert!(actions.is_empty());
701
702 let actions = engine.tick(113.0);
704 assert_eq!(actions.len(), 1);
705 assert_eq!(engine.state(), LinkState::Closed);
706 }
707
708 #[test]
709 fn test_tick_stale_and_close() {
710 let mut rng_id = make_rng(0x01);
711 let dest_sig_prv = Ed25519PrivateKey::generate(&mut rng_id);
712 let dest_sig_pub_bytes = dest_sig_prv.public_key().public_bytes();
713 let dest_hash = [0xDD; 16];
714
715 let mut rng_init = make_rng(0x10);
716 let (mut initiator, request_data) = LinkEngine::new_initiator(
717 &dest_hash, 1, LinkMode::Aes256Cbc, Some(500), 100.0, &mut rng_init,
718 );
719 let mut hashable = Vec::new();
720 hashable.push(0x00);
721 hashable.push(0x00);
722 hashable.extend_from_slice(&dest_hash);
723 hashable.push(0x00);
724 hashable.extend_from_slice(&request_data);
725 initiator.set_link_id_from_hashable(&hashable, request_data.len());
726
727 let mut rng_resp = make_rng(0x20);
728 let (_, lrproof_data) = LinkEngine::new_responder(
729 &dest_sig_prv, &dest_sig_pub_bytes, &request_data, &hashable,
730 &dest_hash, 1, 100.5, &mut rng_resp,
731 ).unwrap();
732
733 let mut rng_lrrtt = make_rng(0x30);
734 initiator.handle_lrproof(&lrproof_data, &dest_sig_pub_bytes, 100.8, &mut rng_lrrtt).unwrap();
735 assert_eq!(initiator.state(), LinkState::Active);
736
737 let stale_time = initiator.stale_time;
739 let actions = initiator.tick(100.8 + stale_time + 1.0);
740 assert_eq!(initiator.state(), LinkState::Stale);
741 assert_eq!(actions.len(), 1);
742
743 let actions = initiator.tick(100.8 + stale_time + 2.0);
745 assert_eq!(initiator.state(), LinkState::Closed);
746 assert_eq!(actions.len(), 1);
747 }
748
749 #[test]
750 fn test_needs_keepalive() {
751 let mut rng_id = make_rng(0x01);
752 let dest_sig_prv = Ed25519PrivateKey::generate(&mut rng_id);
753 let dest_sig_pub_bytes = dest_sig_prv.public_key().public_bytes();
754 let dest_hash = [0xDD; 16];
755
756 let mut rng_init = make_rng(0x10);
757 let (mut initiator, request_data) = LinkEngine::new_initiator(
758 &dest_hash, 1, LinkMode::Aes256Cbc, Some(500), 100.0, &mut rng_init,
759 );
760 let mut hashable = Vec::new();
761 hashable.push(0x00);
762 hashable.push(0x00);
763 hashable.extend_from_slice(&dest_hash);
764 hashable.push(0x00);
765 hashable.extend_from_slice(&request_data);
766 initiator.set_link_id_from_hashable(&hashable, request_data.len());
767
768 let mut rng_resp = make_rng(0x20);
769 let (_, lrproof_data) = LinkEngine::new_responder(
770 &dest_sig_prv, &dest_sig_pub_bytes, &request_data, &hashable,
771 &dest_hash, 1, 100.5, &mut rng_resp,
772 ).unwrap();
773
774 let mut rng_lrrtt = make_rng(0x30);
775 initiator.handle_lrproof(&lrproof_data, &dest_sig_pub_bytes, 100.8, &mut rng_lrrtt).unwrap();
776
777 let ka = initiator.keepalive_interval();
778 assert!(!initiator.needs_keepalive(100.8 + ka - 1.0));
780 assert!(initiator.needs_keepalive(100.8 + ka + 1.0));
782 }
783
784 #[test]
785 fn test_needs_keepalive_responder() {
786 let mut rng_id = make_rng(0x01);
787 let dest_sig_prv = Ed25519PrivateKey::generate(&mut rng_id);
788 let dest_sig_pub_bytes = dest_sig_prv.public_key().public_bytes();
789 let dest_hash = [0xDD; 16];
790
791 let mut rng_init = make_rng(0x10);
792 let (mut initiator, request_data) = LinkEngine::new_initiator(
793 &dest_hash, 1, LinkMode::Aes256Cbc, Some(500), 100.0, &mut rng_init,
794 );
795 let mut hashable = Vec::new();
796 hashable.push(0x00);
797 hashable.push(0x00);
798 hashable.extend_from_slice(&dest_hash);
799 hashable.push(0x00);
800 hashable.extend_from_slice(&request_data);
801 initiator.set_link_id_from_hashable(&hashable, request_data.len());
802
803 let mut rng_resp = make_rng(0x20);
804 let (mut responder, lrproof_data) = LinkEngine::new_responder(
805 &dest_sig_prv, &dest_sig_pub_bytes, &request_data, &hashable,
806 &dest_hash, 1, 100.5, &mut rng_resp,
807 ).unwrap();
808
809 let mut rng_lrrtt = make_rng(0x30);
810 let (lrrtt_encrypted, _) = initiator.handle_lrproof(
811 &lrproof_data, &dest_sig_pub_bytes, 100.8, &mut rng_lrrtt,
812 ).unwrap();
813 responder.handle_lrrtt(&lrrtt_encrypted, 101.0).unwrap();
814
815 let ka = responder.keepalive_interval();
816 assert!(!responder.needs_keepalive(101.0 + ka - 1.0));
818 assert!(responder.needs_keepalive(101.0 + ka + 1.0));
819 }
820
821 #[test]
822 fn test_teardown() {
823 let mut rng = make_rng(0x10);
824 let (mut engine, _) = LinkEngine::new_initiator(
825 &[0xDD; 16], 1, LinkMode::Aes256Cbc, None, 100.0, &mut rng,
826 );
827 let actions = engine.teardown();
828 assert_eq!(engine.state(), LinkState::Closed);
829 assert_eq!(actions.len(), 1);
830
831 let actions = engine.teardown();
833 assert!(actions.is_empty());
834 }
835
836 #[test]
837 fn test_handle_teardown() {
838 let mut rng = make_rng(0x10);
839 let (mut engine, _) = LinkEngine::new_initiator(
840 &[0xDD; 16], 1, LinkMode::Aes256Cbc, None, 100.0, &mut rng,
841 );
842 let actions = engine.handle_teardown();
843 assert_eq!(engine.state(), LinkState::Closed);
844 assert_eq!(actions.len(), 1);
845 match &actions[0] {
846 LinkAction::StateChanged { reason, .. } => {
847 assert_eq!(*reason, Some(TeardownReason::DestinationClosed));
848 }
849 _ => panic!("Expected StateChanged"),
850 }
851 }
852
853 #[test]
854 fn test_identify_over_link() {
855 let mut rng_id = make_rng(0x01);
856 let dest_sig_prv = Ed25519PrivateKey::generate(&mut rng_id);
857 let dest_sig_pub_bytes = dest_sig_prv.public_key().public_bytes();
858 let dest_hash = [0xDD; 16];
859
860 let mut rng_init = make_rng(0x10);
861 let (mut initiator, request_data) = LinkEngine::new_initiator(
862 &dest_hash, 1, LinkMode::Aes256Cbc, Some(500), 100.0, &mut rng_init,
863 );
864 let mut hashable = Vec::new();
865 hashable.push(0x00);
866 hashable.push(0x00);
867 hashable.extend_from_slice(&dest_hash);
868 hashable.push(0x00);
869 hashable.extend_from_slice(&request_data);
870 initiator.set_link_id_from_hashable(&hashable, request_data.len());
871
872 let mut rng_resp = make_rng(0x20);
873 let (mut responder, lrproof_data) = LinkEngine::new_responder(
874 &dest_sig_prv, &dest_sig_pub_bytes, &request_data, &hashable,
875 &dest_hash, 1, 100.5, &mut rng_resp,
876 ).unwrap();
877
878 let mut rng_lrrtt = make_rng(0x30);
879 let (lrrtt_encrypted, _) = initiator.handle_lrproof(
880 &lrproof_data, &dest_sig_pub_bytes, 100.8, &mut rng_lrrtt,
881 ).unwrap();
882 responder.handle_lrrtt(&lrrtt_encrypted, 101.0).unwrap();
883
884 let mut rng_ident = make_rng(0x40);
886 let my_identity = rns_crypto::identity::Identity::new(&mut rng_ident);
887
888 let mut rng_enc = make_rng(0x50);
890 let identify_encrypted = initiator.build_identify(&my_identity, &mut rng_enc).unwrap();
891
892 let actions = responder.handle_identify(&identify_encrypted).unwrap();
893 assert_eq!(actions.len(), 1);
894 match &actions[0] {
895 LinkAction::RemoteIdentified { identity_hash, public_key, .. } => {
896 assert_eq!(identity_hash, my_identity.hash());
897 assert_eq!(public_key, &my_identity.get_public_key().unwrap());
898 }
899 _ => panic!("Expected RemoteIdentified"),
900 }
901 }
902
903 #[test]
904 fn test_aes128_mode_handshake() {
905 let mut rng_id = make_rng(0x01);
906 let dest_sig_prv = Ed25519PrivateKey::generate(&mut rng_id);
907 let dest_sig_pub_bytes = dest_sig_prv.public_key().public_bytes();
908 let dest_hash = [0xDD; 16];
909
910 let mut rng_init = make_rng(0x10);
911 let (mut initiator, request_data) = LinkEngine::new_initiator(
912 &dest_hash, 1, LinkMode::Aes128Cbc, Some(500), 100.0, &mut rng_init,
913 );
914 let mut hashable = Vec::new();
915 hashable.push(0x00);
916 hashable.push(0x00);
917 hashable.extend_from_slice(&dest_hash);
918 hashable.push(0x00);
919 hashable.extend_from_slice(&request_data);
920 initiator.set_link_id_from_hashable(&hashable, request_data.len());
921
922 let mut rng_resp = make_rng(0x20);
923 let (mut responder, lrproof_data) = LinkEngine::new_responder(
924 &dest_sig_prv, &dest_sig_pub_bytes, &request_data, &hashable,
925 &dest_hash, 1, 100.5, &mut rng_resp,
926 ).unwrap();
927
928 let mut rng_lrrtt = make_rng(0x30);
929 let (lrrtt_encrypted, _) = initiator.handle_lrproof(
930 &lrproof_data, &dest_sig_pub_bytes, 100.8, &mut rng_lrrtt,
931 ).unwrap();
932 responder.handle_lrrtt(&lrrtt_encrypted, 101.0).unwrap();
933
934 assert_eq!(initiator.state(), LinkState::Active);
935 assert_eq!(responder.state(), LinkState::Active);
936 assert_eq!(initiator.mode(), LinkMode::Aes128Cbc);
937
938 let mut rng_enc = make_rng(0x40);
940 let ct = initiator.encrypt(b"AES128 test", &mut rng_enc).unwrap();
941 let pt = responder.decrypt(&ct).unwrap();
942 assert_eq!(pt, b"AES128 test");
943 }
944}