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