1use std::{collections, rc::Rc};
4
5use crate::{
6 ake::{AKEContext, CryptographicMaterial},
7 clientprofile::{ClientProfile, ClientProfilePayload},
8 dake::{DAKEContext, MixedKeyMaterial},
9 encoding::{MessageFlags, OTRDecoder, OTREncoder},
10 fragment::{self, FragmentError},
11 instancetag::{self, InstanceTag, INSTANCE_ZERO},
12 messages::{
13 self, encode_message, serialize_message, EncodedMessage, EncodedMessageType, MessageType,
14 },
15 protocol::{self, Message, ProtocolMaterial},
16 smp::{self, SMPStatus},
17 smp4::{self, SMP4Status},
18 utils, Host, OTRError, Policy, ProtocolStatus, UserMessage, Version, SSID, SUPPORTED_VERSIONS,
19};
20
21pub struct Account {
22 host: Rc<dyn Host>,
23 details: Rc<AccountDetails>,
24 profile: ClientProfile,
25 sessions: collections::HashMap<Vec<u8>, Session>,
26}
27
28impl Account {
30 pub fn new(account: Vec<u8>, policy: Policy, host: Rc<dyn Host>) -> Result<Self, OTRError> {
35 let sessions = collections::HashMap::new();
36 let profile = if let Ok(restored) = Self::restore_clientprofile(host.as_ref()) {
37 log::trace!("Account: attempting to restore client-profile from host.");
38 restored
39 } else {
40 log::trace!("Account: host provided zero bytes, incorrect or expired profile. Constructing new client profile.");
41 Self::generate_clientprofile(host.as_ref())
42 };
43 let details = Rc::new(AccountDetails {
44 policy,
45 tag: profile.owner_tag,
46 account,
47 });
48 Ok(Self {
49 host,
50 details,
51 profile,
52 sessions,
53 })
54 }
55
56 fn restore_clientprofile(host: &dyn Host) -> Result<ClientProfile, OTRError> {
58 log::trace!("Account: restoring existing client profile.");
59 let encoded_profile = host.client_profile();
60 let mut decoder = OTRDecoder::new(&encoded_profile);
61 let payload = ClientProfilePayload::decode(&mut decoder)?;
62 decoder.done()?;
63 payload.validate()
64 }
65
66 fn generate_clientprofile(host: &dyn Host) -> ClientProfile {
67 const DEFAULT_EXPIRATION: u64 = 7 * 24 * 3600;
68 let tag = instancetag::random_tag();
69 let identity_keypair = host.keypair_identity();
70 let identity_public = identity_keypair.public().clone();
71 let forging_public = host.keypair_forging().public().clone();
72 let mut versions = vec![Version::V4];
73 let legacy_keypair = host.keypair();
74 if legacy_keypair.is_some() {
75 versions.push(Version::V3);
76 }
77 let expiration = i64::try_from(
78 std::time::SystemTime::now()
79 .checked_add(std::time::Duration::new(DEFAULT_EXPIRATION, 0))
80 .unwrap()
81 .duration_since(std::time::UNIX_EPOCH)
82 .unwrap()
83 .as_secs(),
84 )
85 .expect("BUG: working under the assumption that the duration calculation fits in an i64.");
86 let profile = ClientProfile::new(
87 tag,
88 identity_public,
89 forging_public,
90 versions,
91 expiration,
92 legacy_keypair.map(|keypair| keypair.public_key().clone()),
93 ).expect("BUG: failed to construct new client-profile for our client. This only happens in case of bad input such as illegal keypairs.");
94 let payload = profile.sign(identity_keypair, legacy_keypair);
95 host.update_client_profile(OTREncoder::new().write_encodable(&payload).to_vec());
96 profile
97 }
98
99 #[must_use]
100 pub fn instance_tag(&self) -> InstanceTag {
101 self.details.tag
102 }
103
104 #[must_use]
105 pub fn policy(&self) -> Policy {
106 self.details.policy
107 }
108
109 #[must_use]
110 pub fn session(&mut self, address: &[u8]) -> &mut Session {
111 self.sessions
112 .entry(Vec::from(address))
113 .or_insert(Session::new(
114 Rc::clone(&self.host),
115 Rc::clone(&self.details),
116 Vec::from(address),
117 ))
118 }
119
120 pub fn expire(&mut self, timeout: u64) {
124 for (_, session) in &mut self.sessions {
126 session.expire(timeout);
127 }
128 }
129}
130
131pub struct Session {
132 host: Rc<dyn Host>,
133 details: Rc<AccountDetails>,
134 address: Vec<u8>,
136 instances: collections::HashMap<InstanceTag, Instance>,
140 whitespace_tagged: bool,
147}
148
149impl Session {
151 fn new(host: Rc<dyn Host>, details: Rc<AccountDetails>, address: Vec<u8>) -> Session {
152 let mut instances = collections::HashMap::new();
153 instances.insert(
154 INSTANCE_ZERO,
155 Instance::new(
156 Rc::clone(&details),
157 Rc::clone(&host),
158 address.clone(),
159 INSTANCE_ZERO,
160 ),
161 );
162 Self {
163 host,
164 details,
165 address,
166 instances,
167 whitespace_tagged: false,
168 }
169 }
170
171 #[must_use]
176 pub fn instances(&self) -> Vec<InstanceTag> {
177 let mut sessions = Vec::<InstanceTag>::new();
178 for k in self.instances.keys() {
179 if *k == INSTANCE_ZERO {
180 continue;
181 }
182 sessions.push(*k);
183 }
184 sessions
185 }
186
187 pub fn expire(&mut self, timeout: u64) {
192 for (_, instance) in &mut self.instances {
194 instance.expire(timeout);
195 }
196 }
197
198 pub fn status(&self, instance: InstanceTag) -> Option<ProtocolStatus> {
201 self.instances.get(&instance).map(Instance::status)
202 }
203
204 #[allow(clippy::too_many_lines)]
222 pub fn receive(&mut self, payload: &[u8]) -> Result<UserMessage, OTRError> {
223 log::debug!("Processing incoming message ..");
224 if !self.details.policy.contains(Policy::ALLOW_V3)
225 && !self.details.policy.contains(Policy::ALLOW_V4)
226 {
227 return Ok(UserMessage::Plaintext(Vec::from(payload)));
229 }
230 if fragment::match_fragment(payload) {
231 log::debug!("Processing OTR fragment ..");
232 let Some(fragment) = fragment::parse(payload) else {
233 log::debug!("Not a valid/supported fragment.");
234 return Ok(UserMessage::None);
235 };
236 fragment::verify(&fragment).or(Err(OTRError::ProtocolViolation("Invalid fragment")))?;
237 if fragment.receiver != INSTANCE_ZERO && fragment.receiver != self.details.tag {
238 return Err(OTRError::MessageForOtherInstance);
241 }
242 let details = Rc::clone(&self.details);
243 let instance = self.instances.entry(fragment.sender).or_insert_with(|| {
244 Instance::new(
245 details,
246 Rc::clone(&self.host),
247 self.address.clone(),
248 fragment.sender,
249 )
250 });
251 return match instance.assembler.assemble(&fragment) {
252 Ok(assembled) => {
253 if fragment::match_fragment(&assembled) {
254 return Err(OTRError::ProtocolViolation("Assembled fragments assemble into a fragment. This is disallowed by the specification."));
255 }
256 self.receive(&assembled)
257 }
258 Err(FragmentError::IncompleteResult | FragmentError::UnexpectedFragment) => {
259 Ok(UserMessage::None)
264 }
265 Err(FragmentError::InvalidData) => {
266 Err(OTRError::ProtocolViolation(
270 "Fragment contains invalid data.",
271 ))
272 }
273 };
274 }
275 match messages::parse(payload)? {
277 MessageType::Error(error) => {
278 log::debug!("Processing OTR Error message ..");
279 if self.details.policy.contains(Policy::ERROR_START_AKE) {
280 self.query()?;
281 }
282 Ok(UserMessage::Error(error))
283 }
284 MessageType::Plaintext(content) => {
285 log::debug!("Processing plaintext message ..");
286 if self.has_sessions() || self.details.policy.contains(Policy::REQUIRE_ENCRYPTION) {
287 Ok(UserMessage::WarningUnencrypted(content))
288 } else {
289 Ok(UserMessage::Plaintext(content))
290 }
291 }
292 MessageType::Tagged(versions, content) => {
293 log::debug!("Processing whitespace-tagged message ..");
294 if self.details.policy.contains(Policy::WHITESPACE_START_AKE) {
295 if let Some(selected) = select_version(&self.details.policy, &versions) {
296 self.initiate(&selected, INSTANCE_ZERO)?;
297 }
298 }
299 if self.has_sessions() || self.details.policy.contains(Policy::REQUIRE_ENCRYPTION) {
300 Ok(UserMessage::WarningUnencrypted(content))
301 } else {
302 Ok(UserMessage::Plaintext(content))
303 }
304 }
305 MessageType::Query(versions) => {
306 log::debug!("Processing query message ..");
307 log::trace!("Query-message with versions {:?}", versions);
308 if let Some(selected) = select_version(&self.details.policy, &versions) {
309 self.initiate(&selected, INSTANCE_ZERO)?;
310 }
311 Ok(UserMessage::None)
312 }
313 MessageType::Encoded(EncodedMessage {
314 version: _,
315 sender: 0,
316 receiver: _,
317 message: _,
318 }) => {
319 log::debug!("Encoded message with sender-tag 0. This is illegal in OTR protocol (starting with version 3).");
320 Ok(UserMessage::None)
321 }
322 MessageType::Encoded(
323 msg @ EncodedMessage {
324 version: Version::V3,
325 sender: _,
326 receiver: _,
327 message: EncodedMessageType::DHKey(_),
328 },
329 ) => {
330 log::debug!("Processing OTR-encoded D-H Commit message (with possible need to transfer AKEContext)…");
331 self.verify_encoded_message_header(&msg)?;
338 if !self.details.policy.contains(Policy::ALLOW_V3) {
339 return Ok(UserMessage::None);
340 }
341 let result_context = self
345 .instances
346 .get(&INSTANCE_ZERO)
347 .expect("BUG: instance 0 should always exist.")
348 .transfer_ake_context();
349 let instance = self.instances.entry(msg.sender).or_insert_with(|| {
350 Instance::new(
351 Rc::clone(&self.details),
352 Rc::clone(&self.host),
353 self.address.clone(),
354 msg.sender,
355 )
356 });
357 if let Ok(context) = result_context {
358 instance.adopt_ake_context(context);
359 }
360 instance.handle(msg)
361 }
362 MessageType::Encoded(
363 msg @ EncodedMessage {
364 version: Version::V4,
365 sender: _,
366 receiver: _,
367 message: EncodedMessageType::AuthR(_),
368 },
369 ) => {
370 log::debug!("Processing OTR-encoded Auth-R message (with possible need to transfer DAKEContext)…");
372 log::trace!("Auth-R message: {msg:?}");
373 self.verify_encoded_message_header(&msg)?;
374 if !self.details.policy.contains(Policy::ALLOW_V4) {
375 return Ok(UserMessage::None);
376 }
377 let result_context = self
381 .instances
382 .get(&INSTANCE_ZERO)
383 .expect("BUG: instance 0 should always exist.")
384 .transfer_dake_context();
385 let instance = self.instances.entry(msg.sender).or_insert_with(|| {
386 Instance::new(
387 Rc::clone(&self.details),
388 Rc::clone(&self.host),
389 self.address.clone(),
390 msg.sender,
391 )
392 });
393 if let Ok(context) = result_context {
395 instance.adopt_dake_context(context);
396 }
397 instance.handle(msg)
398 }
399 MessageType::Encoded(msg) => {
400 log::debug!("Processing OTR-encoded message…");
401 log::trace!("Encoded message: {msg:?}");
402 self.verify_encoded_message_header(&msg)?;
403 if msg.version == Version::V3 && !self.details.policy.contains(Policy::ALLOW_V3)
404 || msg.version == Version::V4 && !self.details.policy.contains(Policy::ALLOW_V4)
405 {
406 return Ok(UserMessage::None);
407 }
408 self.instances
409 .entry(msg.sender)
410 .or_insert_with(|| {
411 Instance::new(
412 Rc::clone(&self.details),
413 Rc::clone(&self.host),
414 self.address.clone(),
415 msg.sender,
416 )
417 })
418 .handle(msg)
419 }
420 }
421 }
422
423 fn verify_encoded_message_header(&self, msg: &EncodedMessage) -> Result<(), OTRError> {
424 match msg.version {
425 Version::None => {
426 return Err(OTRError::ProtocolViolation(
427 "Encoded message must always have a protocol version.",
428 ))
429 }
430 Version::Unsupported(version) => return Err(OTRError::UnsupportedVersion(version)),
431 Version::V3 | Version::V4 => { }
432 }
433 instancetag::verify(msg.sender).or(Err(OTRError::ProtocolViolation(
434 "Sender instance tag is illegal value",
435 )))?;
436 if msg.sender == INSTANCE_ZERO {
437 return Err(OTRError::ProtocolViolation("Sender instance tag is zero"));
438 }
439 instancetag::verify(msg.receiver).or(Err(OTRError::ProtocolViolation(
440 "Receiver instance tag is illegal value",
441 )))?;
442 if msg.receiver == 0
443 && !matches!(
444 msg.message,
445 EncodedMessageType::DHCommit(_) | EncodedMessageType::Identity(_)
446 )
447 {
448 return Err(OTRError::ProtocolViolation(
449 "Receiver instance tag is zero.",
450 ));
451 }
452 if msg.receiver > INSTANCE_ZERO && msg.receiver != self.details.tag {
453 return Err(OTRError::MessageForOtherInstance);
454 }
455 Ok(())
456 }
457
458 pub fn send(
478 &mut self,
479 instance: InstanceTag,
480 content: &[u8],
481 ) -> Result<Vec<Vec<u8>>, OTRError> {
482 if !self.details.policy.contains(Policy::ALLOW_V3)
483 && !self.details.policy.contains(Policy::ALLOW_V4)
484 {
485 log::debug!("No protocol versions are allowed. OTR support is disabled.");
486 return Ok(vec![Vec::from(content)]);
487 }
488 let instance = self
489 .instances
490 .get_mut(&instance)
491 .ok_or(OTRError::UnknownInstance(instance))?;
492 if self.details.policy.contains(Policy::REQUIRE_ENCRYPTION)
494 && instance.status() == ProtocolStatus::Plaintext
495 {
496 self.query()?;
500 return Err(OTRError::PolicyRestriction(
501 "Encryption is required by policy, but no confidential session is established yet. Query-message has been sent to initiate OTR session.",
502 ));
503 }
504 instance.send(&mut self.whitespace_tagged, content)
511 }
512
513 pub fn initiate(
519 &mut self,
520 version: &Version,
521 receiver: InstanceTag,
522 ) -> Result<UserMessage, OTRError> {
523 self.instances
524 .entry(receiver)
525 .or_insert_with(|| {
526 Instance::new(
527 Rc::clone(&self.details),
528 Rc::clone(&self.host),
529 self.address.clone(),
530 receiver,
531 )
532 })
533 .initiate(version)
534 }
535
536 pub fn ssid(&self, instance: InstanceTag) -> Result<SSID, OTRError> {
544 self.instances
545 .get(&instance)
546 .ok_or(OTRError::UnknownInstance(instance))?
547 .ssid()
548 }
549
550 fn get_instance(&mut self, instance: InstanceTag) -> Result<&mut Instance, OTRError> {
551 self.instances
552 .get_mut(&instance)
553 .ok_or(OTRError::UnknownInstance(instance))
554 }
555
556 fn has_sessions(&self) -> bool {
558 self.instances.iter().any(|i| {
559 assert_eq!(*i.0, i.1.receiver);
560 assert!(
561 *i.0 != INSTANCE_ZERO || i.1.status() == ProtocolStatus::Plaintext,
562 "BUG: Given that we do not support OTR version 1 and 2, we expect instance 0 is Plaintext"
563 );
564 i.1.status() == ProtocolStatus::Encrypted || i.1.status() == ProtocolStatus::Finished
565 })
566 }
567
568 pub fn end(&mut self, instance: InstanceTag) -> Result<UserMessage, OTRError> {
580 Ok(self.get_instance(instance)?.reset())
581 }
582
583 pub fn query(&mut self) -> Result<(), OTRError> {
590 let accepted_versions = filter_versions(&self.details.policy, &SUPPORTED_VERSIONS);
591 if accepted_versions.is_empty() {
592 return Err(OTRError::UserError("No supported versions available."));
593 }
594 self.host.inject(
595 &self.address,
596 &serialize_message(&MessageType::Query(accepted_versions)),
597 );
598 Ok(())
599 }
600
601 pub fn start_smp(
610 &mut self,
611 instance: InstanceTag,
612 secret: &[u8],
613 question: &[u8],
614 ) -> Result<(), OTRError> {
615 self.get_instance(instance)?.start_smp(secret, question)
616 }
617
618 pub fn abort_smp(&mut self, instance: InstanceTag) -> Result<(), OTRError> {
625 self.get_instance(instance)?.abort_smp()
626 }
627}
628
629struct Instance {
631 details: Rc<AccountDetails>,
632 host: Rc<dyn Host>,
633 address: Vec<u8>,
634 receiver: InstanceTag,
635 assembler: fragment::Assembler,
637 state: Box<dyn protocol::ProtocolState>,
638 ake: AKEContext,
639 dake: DAKEContext,
640}
641
642impl Instance {
648 fn new(
649 details: Rc<AccountDetails>,
650 host: Rc<dyn Host>,
651 address: Vec<u8>,
652 receiver: InstanceTag,
653 ) -> Self {
654 Self {
655 ake: AKEContext::new(Rc::clone(&host)),
656 dake: DAKEContext::new(Rc::clone(&host)),
657 details,
658 host,
659 address,
660 receiver,
661 assembler: fragment::Assembler::new(),
662 state: protocol::new_state(),
663 }
664 }
665
666 fn status(&self) -> ProtocolStatus {
667 self.state.status()
668 }
669
670 fn expire(&mut self, timeout: u64) {
671 if let Some((disconnect_msg, new_state)) = self.state.expire(timeout) {
673 let prev = core::mem::replace(
674 &mut self.state,
675 new_state as Box<dyn protocol::ProtocolState>,
676 );
677 self.inject(&prev.version(), self.receiver, disconnect_msg);
678 }
679 }
680
681 fn initiate(&mut self, version: &Version) -> Result<UserMessage, OTRError> {
682 let initiator = match version {
683 Version::V3 => self.ake.initiate(),
684 Version::V4 => self.dake.initiate()?,
685 Version::None | Version::Unsupported(_) => panic!("BUG: incorrect use of API"),
686 };
687 self.inject(version, self.receiver, initiator);
688 Ok(UserMessage::None)
689 }
690
691 fn transfer_ake_context(&self) -> Result<AKEContext, OTRError> {
692 assert_eq!(INSTANCE_ZERO, self.receiver);
693 self.ake.transfer().map_err(OTRError::AuthenticationError)
694 }
695
696 fn adopt_ake_context(&mut self, context: AKEContext) {
697 assert_ne!(0, self.receiver);
698 log::trace!("OTR AKE state transferred.");
699 self.ake = context;
700 }
701
702 fn transfer_dake_context(&self) -> Result<DAKEContext, OTRError> {
703 assert_eq!(INSTANCE_ZERO, self.receiver);
704 self.dake.transfer()
705 }
706
707 fn adopt_dake_context(&mut self, context: DAKEContext) {
708 assert_ne!(0, self.receiver);
709 log::trace!("OTRv4 DAKE state transferred.");
710 self.dake = context;
711 }
712
713 #[allow(clippy::too_many_lines)]
715 fn handle(&mut self, encoded_message: EncodedMessage) -> Result<UserMessage, OTRError> {
716 let version = encoded_message.version;
719 let sender = encoded_message.sender;
720 let receiver = encoded_message.receiver;
721 if version == Version::V3 {
722 self.assembler.cleanup(&Version::V3);
723 }
724 match (&version, encoded_message.message) {
725 (Version::V3, EncodedMessageType::DHCommit(msg)) => {
726 let response = self
727 .ake
728 .handle_dhcommit(msg).map_err(OTRError::AuthenticationError)?;
729 self.inject(&self.ake.version(), sender, response);
730 Ok(UserMessage::None)
731 }
732 (Version::V3, EncodedMessageType::DHKey(msg)) => {
733 let response = self
734 .ake
735 .handle_dhkey(msg).map_err(OTRError::AuthenticationError)?;
736 self.inject(&self.ake.version(), sender, response);
737 Ok(UserMessage::None)
738 }
739 (Version::V3, EncodedMessageType::RevealSignature(msg)) => {
740 let (CryptographicMaterial{ssid, our_dh, their_dh, their_dsa}, response) = self
741 .ake
742 .handle_reveal_signature(msg).map_err(OTRError::AuthenticationError)?;
743 self.state = self.state.secure(Rc::clone(&self.host), self.details.tag,
744 encoded_message.sender, ProtocolMaterial::AKE { ssid, our_dh, their_dh, their_dsa });
745 assert_eq!(ProtocolStatus::Encrypted, self.state.status());
746 self.inject(&self.ake.version(), sender, response);
747 Ok(UserMessage::ConfidentialSessionStarted(self.receiver))
748 }
749 (Version::V3, EncodedMessageType::Signature(msg)) => {
750 let CryptographicMaterial{ssid, our_dh, their_dh, their_dsa} = self
751 .ake
752 .handle_signature(msg).map_err(OTRError::AuthenticationError)?;
753 self.state = self.state.secure(Rc::clone(&self.host), self.details.tag,
754 encoded_message.sender, ProtocolMaterial::AKE { ssid, our_dh, their_dh, their_dsa });
755 assert_eq!(ProtocolStatus::Encrypted, self.state.status());
756 Ok(UserMessage::ConfidentialSessionStarted(self.receiver))
757 }
758 (Version::V3, EncodedMessageType::Data(msg)) => {
759 let authenticator_data = messages::encode_authenticator_data(&version, sender, receiver, &msg);
763 let (message, transition) = self.state.handle(&msg, &authenticator_data);
764 if transition.is_some() {
765 self.state = transition.unwrap();
766 }
767 match message {
768 Ok(Message::Confidential(content, tlvs)) if tlvs.iter().any(smp::is_smp_tlv) => {
769 if !msg.flags.contains(MessageFlags::IGNORE_UNREADABLE) {
770 log::warn!("Other client did not set ignore-unreadable flag on SMP messages. This is preferred/recommended because these are OTR control messages, rather than user content.");
771 }
772 if !content.is_empty() {
773 log::warn!("OTR3 SMP tlv messages are not expected to contain text content. This content is ignored.");
774 }
775 if tlvs.iter().filter(|t| smp::is_smp_tlv(t)).count() > 1 {
776 log::warn!("OTR3 more than one SMP tlv found. This is not expected according to the specification. Aborting further processing.");
780 return Err(OTRError::ProtocolViolation("SMP: more than one SMP tlv found. This cannot occur when protocol is properly followed."));
781 }
782 let Ok(smp_context) = self.state.smp_mut() else {
783 log::warn!("OTR3 SMP state is no longer available. The state machine must have transitioned away before the SMP tlvs were processed. This seems to indicate a protocol violation. Ignoring this SMP tlv and returning result without user-content.");
787 return Err(OTRError::ProtocolViolation("OTR3 SMP tlv being processed while the state machine has already transitioned away. This cannot happen in OTR unless the other client deviated from the protocol."));
788 };
789 let tlv = tlvs.into_iter().find(smp::is_smp_tlv).unwrap();
791 if let Some(reply_tlv) = smp_context.handle(&tlv) {
792 let otr_message = self.state.prepare(
793 MessageFlags::IGNORE_UNREADABLE,
794 &OTREncoder::new()
795 .write_u8(0)
796 .write_tlv(&reply_tlv)
797 .to_vec())?;
798 self.inject(&self.state.version(), sender, otr_message);
800 }
801 match self.state.smp().unwrap().status() {
802 SMPStatus::InProgress => Ok(UserMessage::None),
803 SMPStatus::Completed => Ok(UserMessage::SMPSucceeded(self.receiver)),
804 SMPStatus::Aborted(_) => Ok(UserMessage::SMPFailed(self.receiver)),
805 SMPStatus::Initial => panic!("BUG: we should be able to reach after having processed an SMP message TLV."),
806 }
807 }
808 Ok(Message::Confidential(content, tlvs)) => Ok(UserMessage::Confidential(self.receiver, content, tlvs)),
809 Ok(Message::ConfidentialFinished(content)) => Ok(UserMessage::ConfidentialSessionFinished(self.receiver, content)),
810 Err(OTRError::UnreadableMessage(_)) if msg.flags.contains(MessageFlags::IGNORE_UNREADABLE) => {
811 self.host.inject(&self.address, &serialize_message(&MessageType::Error(
815 Vec::from("unreadable message")
816 )));
817 Ok(UserMessage::None)
818 }
819 Err(OTRError::UnreadableMessage(_)) => {
820 self.host.inject(&self.address, &serialize_message(&MessageType::Error(
821 Vec::from("unreadable message")
822 )));
823 Err(OTRError::UnreadableMessage(self.receiver))
824 }
825 Err(error) => {
826 log::debug!("Received unexpected error-type: {:?}", &error);
828 Err(error)
829 }
830 }
831 }
832 (Version::V4, EncodedMessageType::Identity(message)) => {
833 let response = self.dake.handle_identity(message, &self.details.account, &self.address)?;
834 self.inject(&self.dake.version(), sender, response);
835 Ok(UserMessage::None)
836 }
837 (Version::V4, EncodedMessageType::AuthR(message)) => {
838 let (MixedKeyMaterial{ssid, double_ratchet, us, them}, response) = self.dake.handle_auth_r(message, &self.details.account, &self.address)?;
839 self.inject(&self.dake.version(), sender, response);
840 self.state = self.state.secure(Rc::clone(&self.host), self.details.tag, self.receiver, ProtocolMaterial::DAKE { ssid, double_ratchet, us, them });
841 assert_eq!(ProtocolStatus::Encrypted, self.state.status());
843 Ok(UserMessage::ConfidentialSessionStarted(self.receiver))
844 }
845 (Version::V4, EncodedMessageType::AuthI(message)) => {
846 let MixedKeyMaterial{ssid, double_ratchet, us, them} = self.dake.handle_auth_i(message, &self.details.account, &self.address)?;
847 self.state = self.state.secure(Rc::clone(&self.host), self.details.tag, self.receiver, ProtocolMaterial::DAKE { ssid, double_ratchet, us, them });
848 assert_eq!(ProtocolStatus::Encrypted, self.state.status());
850 Ok(UserMessage::ConfidentialSessionStarted(self.receiver))
851 }
852 (Version::V4, EncodedMessageType::Data4(msg)) => {
853 msg.validate()?;
854 let authenticator_data = messages::encode_authenticator_data4(&version, sender, receiver, &msg);
858 let (message, transition) = self.state.handle4(&msg, &authenticator_data);
859 if transition.is_some() {
860 self.state = transition.unwrap();
861 }
862 match message {
863 Ok(Message::Confidential(content, tlvs)) if tlvs.iter().any(smp4::is_smp_tlv) => {
864 if !msg.flags.contains(MessageFlags::IGNORE_UNREADABLE) {
865 log::warn!("Other client did not set IGNORE_UNREADABLE flag on SMP messages. This is preferred/recommended because these are OTR control messages, rather than user content.");
866 }
867 if !content.is_empty() {
868 log::warn!("OTRv4 SMP tlv messages are not expected to contain text content. This content is ignored.");
869 }
870 if tlvs.iter().filter(|t| smp4::is_smp_tlv(t)).count() > 1 {
871 log::warn!("OTRv4 more than one SMP tlv found. This is not expected according to the specification. Aborting further processing.");
875 return Err(OTRError::ProtocolViolation("SMP: more than one SMP tlv found. This cannot occur when protocol is properly followed."));
876 }
877 let Ok(smp4_context) = self.state.smp4_mut() else {
878 log::warn!("OTRv4 SMP state is no longer available. The state machine must have transitioned away before the SMP tlvs were processed. This seems to indicate a protocol violation. Ignoring this SMP tlv and returning result without user-content.");
882 return Err(OTRError::ProtocolViolation("OTRv4 SMP tlv being processed while the state machine has already transitioned away. This cannot happen in OTR unless the other client deviated from the protocol."));
883 };
884 let tlv = tlvs.into_iter().find(smp4::is_smp_tlv).unwrap();
886 if let Some(response) = smp4_context.handle(&tlv) {
887 let otr_message = self.state.prepare(
888 MessageFlags::IGNORE_UNREADABLE,
889 &OTREncoder::new()
890 .write_u8(0)
891 .write_tlv(&response)
892 .to_vec())?;
893 self.inject(&self.state.version(), sender, otr_message);
895 }
896 match self.state.smp4().unwrap().status() {
897 SMP4Status::InProgress => Ok(UserMessage::None),
898 SMP4Status::Completed => Ok(UserMessage::SMPSucceeded(self.receiver)),
899 SMP4Status::Aborted(_) => Ok(UserMessage::SMPFailed(self.receiver)),
900 SMP4Status::Initial => panic!("BUG: we should be able to reach after having processed an SMP message TLV."),
901 }
902 }
903 Ok(Message::Confidential(content, tlvs)) => Ok(UserMessage::Confidential(self.receiver, content, tlvs)),
904 Ok(Message::ConfidentialFinished(content)) => Ok(UserMessage::ConfidentialSessionFinished(self.receiver, content)),
905 Err(OTRError::UnreadableMessage(_)) if msg.flags.contains(MessageFlags::IGNORE_UNREADABLE) => {
906 log::debug!("Received unreadable message with flags {}", msg.flags.bits());
907 self.host.inject(&self.address, &serialize_message(&MessageType::Error(
911 Vec::from("unreadable message")
912 )));
913 Ok(UserMessage::None)
914 }
915 Err(OTRError::UnreadableMessage(_)) => {
916 self.host.inject(&self.address, &serialize_message(&MessageType::Error(
917 Vec::from("unreadable message")
918 )));
919 Err(OTRError::UnreadableMessage(self.receiver))
920 }
921 Err(error) => {
922 log::debug!("Received unexpected error-type: {:?}", &error);
924 Err(error)
925 }
926 }
927 }
928 (_, EncodedMessageType::Unencoded(_)) => panic!("BUG: this message-type is used as a placeholder. It can never be an incoming message-type to be handled."),
929 _ => Err(OTRError::ProtocolViolation("Illegal encoded message. Message ignored."))
930 }
931 }
932
933 fn reset(&mut self) -> UserMessage {
934 let previous = self.state.status();
935 let version = self.state.version();
936 let (abortmsg, newstate) = self.state.finish();
937 self.state = newstate;
938 if previous == self.state.status() {
939 assert!(abortmsg.is_none());
940 return UserMessage::None;
941 }
942 if let Some(msg) = abortmsg {
943 self.inject(&version, self.receiver, msg);
944 }
945 UserMessage::Reset(self.receiver)
946 }
947
948 fn send(
949 &mut self,
950 whitespace_tagged: &mut bool,
951 plaintext: &[u8],
952 ) -> Result<Vec<Vec<u8>>, OTRError> {
953 let plaintext = utils::bytes::drop_by_value(plaintext, 0);
954 match self.state.prepare(MessageFlags::empty(), &plaintext)? {
955 EncodedMessageType::Unencoded(msg) => {
956 log::trace!("Message prepared as unencoded message.");
957 assert_eq!(
958 ProtocolStatus::Plaintext,
959 self.state.status(),
960 "BUG: received undefined message type in status {:?}",
961 self.state.status()
962 );
963 let versions = filter_versions(&self.details.policy, &SUPPORTED_VERSIONS);
964 let message = if self.details.policy.contains(Policy::SEND_WHITESPACE_TAG)
965 && !*whitespace_tagged
966 && !versions.is_empty()
967 {
968 *whitespace_tagged = true;
969 MessageType::Tagged(versions, msg)
970 } else {
971 MessageType::Plaintext(msg)
972 };
973 Ok(vec![serialize_message(&message)])
974 }
975 message @ (EncodedMessageType::DHCommit(_)
976 | EncodedMessageType::DHKey(_)
977 | EncodedMessageType::RevealSignature(_)
978 | EncodedMessageType::Signature(_)) => {
979 log::trace!("Message prepared as OTR-encoded protocol message.");
980 let content = encode_message(
981 &self.ake.version(),
982 self.details.tag,
983 self.receiver,
984 message,
985 );
986 Ok(self.prepare_payloads(&self.ake.version(), content))
987 }
988 message @ (EncodedMessageType::Identity(_)
989 | EncodedMessageType::AuthR(_)
990 | EncodedMessageType::AuthI(_)) => {
991 log::trace!("Message prepared as OTR-encoded OTRv4 protocol message.");
992 let content = encode_message(
993 &self.dake.version(),
994 self.details.tag,
995 self.receiver,
996 message,
997 );
998 Ok(self.prepare_payloads(&self.dake.version(), content))
999 }
1000 message @ (EncodedMessageType::Data(_) | EncodedMessageType::Data4(_)) => {
1001 let content = encode_message(
1002 &self.state.version(),
1003 self.details.tag,
1004 self.receiver,
1005 message,
1006 );
1007 Ok(self.prepare_payloads(&self.state.version(), content))
1008 }
1009 }
1010 }
1011
1012 fn prepare_payloads(&self, version: &Version, payload: Vec<u8>) -> Vec<Vec<u8>> {
1013 let max_size = self.host.message_size();
1014 if payload.len() <= max_size {
1015 vec![payload]
1017 } else {
1018 fragment::fragment(max_size, version, self.details.tag, self.receiver, &payload)
1020 .iter()
1021 .map(|f| OTREncoder::new().write_encodable(f).to_vec())
1022 .collect()
1023 }
1024 }
1025
1026 fn start_smp(&mut self, secret: &[u8], question: &[u8]) -> Result<(), OTRError> {
1027 let version = self.state.version();
1030 let tlv = match (&self.state.status(), &version) {
1031 (ProtocolStatus::Encrypted, Version::V3) => {
1032 self.state.smp_mut()?.initiate(secret, question)?
1033 }
1034 (ProtocolStatus::Encrypted, Version::V4) => {
1035 self.state.smp4_mut()?.initiate(secret, question)?
1036 }
1037 _ => {
1038 return Err(OTRError::IncorrectState(
1039 "Session is not in a supported state.",
1040 ))
1041 }
1042 };
1043 let message = self.state.prepare(
1044 MessageFlags::IGNORE_UNREADABLE,
1045 &OTREncoder::new().write_u8(0).write_tlv(&tlv).to_vec(),
1046 )?;
1047 self.inject(&version, self.receiver, message);
1048 Ok(())
1049 }
1050
1051 fn ssid(&self) -> Result<SSID, OTRError> {
1052 match (&self.state.status(), &self.state.version()) {
1053 (ProtocolStatus::Encrypted, Version::V3) => Ok(self.state.smp()?.ssid()),
1054 (ProtocolStatus::Encrypted, Version::V4) => Ok(self.state.smp4()?.ssid()),
1055 _ => Err(OTRError::IncorrectState(
1056 "Session is not in a supported state to acquire SSID for SMP.",
1057 )),
1058 }
1059 }
1060
1061 fn abort_smp(&mut self) -> Result<(), OTRError> {
1062 let tlv = match (&self.state.status(), &self.state.version()) {
1063 (ProtocolStatus::Encrypted, Version::V3) => self.state.smp_mut()?.abort(),
1064 (ProtocolStatus::Encrypted, Version::V4) => self.state.smp4_mut()?.abort(),
1065 _ => {
1066 return Err(OTRError::IncorrectState(
1067 "SMP is not available in current protocol state.",
1068 ))
1069 }
1070 };
1071 let msg = self
1072 .state
1073 .prepare(
1074 MessageFlags::IGNORE_UNREADABLE,
1075 &OTREncoder::new().write_u8(0).write_tlv(&tlv).to_vec(),
1076 )
1077 .unwrap();
1078 self.inject(&self.state.version(), self.receiver, msg);
1079 Ok(())
1080 }
1081
1082 fn inject(&self, version: &Version, receiver: InstanceTag, message: EncodedMessageType) {
1083 assert!(receiver != 0 && self.receiver == 0 || self.receiver == receiver);
1084 log::trace!(
1085 "Injecting encoded message with tag '{}' for '{}'.",
1086 self.details.tag,
1087 receiver
1088 );
1089 let content = encode_message(version, self.details.tag, self.receiver, message);
1090 let max_size = self.host.message_size();
1091 if content.len() <= max_size {
1092 self.host.inject(&self.address, &content);
1093 } else {
1094 for fragment in
1095 fragment::fragment(max_size, version, self.details.tag, self.receiver, &content)
1096 .into_iter()
1097 .map(|f| OTREncoder::new().write_encodable(&f).to_vec())
1098 {
1099 self.host.inject(&self.address, &fragment);
1100 }
1101 }
1102 }
1103}
1104
1105struct AccountDetails {
1107 policy: Policy,
1108 tag: InstanceTag,
1110 account: Vec<u8>,
1111}
1112
1113#[allow(clippy::trivially_copy_pass_by_ref)]
1114fn select_version(policy: &Policy, versions: &[Version]) -> Option<Version> {
1115 if versions.contains(&Version::V4) && policy.contains(Policy::ALLOW_V4) {
1116 Some(Version::V4)
1117 } else if versions.contains(&Version::V3) && policy.contains(Policy::ALLOW_V3) {
1118 Some(Version::V3)
1119 } else {
1120 None
1121 }
1122}
1123
1124#[allow(clippy::trivially_copy_pass_by_ref)]
1125fn filter_versions(policy: &Policy, versions: &[Version]) -> Vec<Version> {
1126 if versions.contains(&Version::V4) && policy.contains(Policy::ALLOW_V4) {
1127 vec![Version::V4]
1128 } else if versions.contains(&Version::V3) && policy.contains(Policy::ALLOW_V3) {
1129 vec![Version::V3]
1130 } else {
1131 Vec::new()
1132 }
1133}
1134
1135#[allow(clippy::too_many_lines)]
1136#[cfg(test)]
1137mod tests {
1138
1139 use std::{cell::RefCell, collections::VecDeque, rc::Rc};
1140
1141 use crate::{
1142 crypto::{dsa, ed448},
1143 instancetag::INSTANCE_ZERO,
1144 Host, OTRError, Policy, ProtocolStatus, UserMessage,
1145 };
1146
1147 use super::{Account, Session};
1148
1149 #[allow(clippy::let_underscore_untyped)]
1150 fn init() {
1151 let _ = env_logger::builder()
1152 .is_test(true)
1153 .filter_level(log::LevelFilter::Trace)
1154 .try_init();
1155 }
1156
1157 #[test]
1161 fn test_plaintext_conversation() {
1162 init();
1163 let keypair_alice = dsa::Keypair::generate();
1166 let identity_alice = ed448::EdDSAKeyPair::generate();
1167 let forging_alice = ed448::EdDSAKeyPair::generate();
1168 let mut messages_alice: Rc<RefCell<VecDeque<Vec<u8>>>> =
1169 Rc::new(RefCell::new(VecDeque::new()));
1170
1171 let keypair_bob = dsa::Keypair::generate();
1172 let identity_bob = ed448::EdDSAKeyPair::generate();
1173 let forging_bob = ed448::EdDSAKeyPair::generate();
1174 let mut messages_bob: Rc<RefCell<VecDeque<Vec<u8>>>> =
1175 Rc::new(RefCell::new(VecDeque::new()));
1176
1177 let host_alice: Rc<dyn Host> = Rc::new(TestHost(
1178 Rc::clone(&messages_bob),
1179 keypair_alice,
1180 usize::MAX,
1181 identity_alice,
1182 forging_alice,
1183 RefCell::new(Vec::new()),
1184 ));
1185 let mut account_alice =
1186 Account::new(Vec::from("alice"), Policy::ALLOW_V3, Rc::clone(&host_alice)).unwrap();
1187 let alice = account_alice.session(b"bob");
1188 let host_bob: Rc<dyn Host> = Rc::new(TestHost(
1189 Rc::clone(&messages_alice),
1190 keypair_bob,
1191 usize::MAX,
1192 identity_bob,
1193 forging_bob,
1194 RefCell::new(Vec::new()),
1195 ));
1196 let mut account_bob =
1197 Account::new(Vec::from("bob"), Policy::ALLOW_V3, Rc::clone(&host_bob)).unwrap();
1198 let bob = account_bob.session(b"alice");
1199
1200 messages_bob
1201 .borrow_mut()
1202 .extend(alice.send(INSTANCE_ZERO, b"Hello bob!").unwrap());
1203 handle_messages("Bob", &mut messages_bob, bob);
1204 messages_alice
1205 .borrow_mut()
1206 .extend(bob.send(INSTANCE_ZERO, b"Hello Alice!").unwrap());
1207 handle_messages("Alice", &mut messages_alice, alice);
1208 }
1209
1210 #[test]
1211 fn test_my_first_otr_session() {
1212 init();
1213 let keypair_alice = dsa::Keypair::generate();
1219 let identity_alice = ed448::EdDSAKeyPair::generate();
1220 let forging_alice = ed448::EdDSAKeyPair::generate();
1221 let mut messages_alice: Rc<RefCell<VecDeque<Vec<u8>>>> =
1222 Rc::new(RefCell::new(VecDeque::new()));
1223
1224 let keypair_bob = dsa::Keypair::generate();
1225 let identity_bob = ed448::EdDSAKeyPair::generate();
1226 let forging_bob = ed448::EdDSAKeyPair::generate();
1227 let mut messages_bob: Rc<RefCell<VecDeque<Vec<u8>>>> =
1228 Rc::new(RefCell::new(VecDeque::new()));
1229
1230 let host_alice: Rc<dyn Host> = Rc::new(TestHost(
1231 Rc::clone(&messages_bob),
1232 keypair_alice,
1233 usize::MAX,
1234 identity_alice,
1235 forging_alice,
1236 RefCell::new(Vec::new()),
1237 ));
1238 let mut account_alice =
1239 Account::new(Vec::from("alice"), Policy::ALLOW_V3, Rc::clone(&host_alice)).unwrap();
1240 let alice = account_alice.session(b"bob");
1241 let host_bob: Rc<dyn Host> = Rc::new(TestHost(
1242 Rc::clone(&messages_alice),
1243 keypair_bob,
1244 usize::MAX,
1245 identity_bob,
1246 forging_bob,
1247 RefCell::new(Vec::new()),
1248 ));
1249 let mut account_bob =
1250 Account::new(Vec::from("bob"), Policy::ALLOW_V3, Rc::clone(&host_bob)).unwrap();
1251 let bob = account_bob.session(b"alice");
1252
1253 alice.query().unwrap();
1254 assert!(handle_messages("Alice", &mut messages_alice, alice).is_none());
1255 assert!(handle_messages("Bob", &mut messages_bob, bob).is_none());
1256 assert!(handle_messages("Alice", &mut messages_alice, alice).is_none());
1257 assert!(handle_messages("Bob", &mut messages_bob, bob).is_none());
1258 let result = handle_messages("Alice", &mut messages_alice, alice).unwrap();
1259 let UserMessage::ConfidentialSessionStarted(tag_bob) = result else {
1260 panic!("BUG: expected confidential session to have started now.")
1261 };
1262 assert_eq!(Some(ProtocolStatus::Encrypted), alice.status(tag_bob));
1263 messages_bob.borrow_mut().extend(
1264 alice
1265 .send(tag_bob, b"Hello Bob! Are we chatting confidentially now?")
1266 .unwrap(),
1267 );
1268 let result = handle_messages("Bob", &mut messages_bob, bob).unwrap();
1269 let UserMessage::ConfidentialSessionStarted(tag_alice) = result else {
1270 panic!("BUG: expected confidential session to have started now.")
1271 };
1272 assert_eq!(Some(ProtocolStatus::Encrypted), bob.status(tag_alice));
1273 assert!(matches!(
1274 handle_messages("Bob", &mut messages_bob, bob),
1275 Some(UserMessage::Confidential(_, _, _))
1276 ));
1277 messages_alice
1278 .borrow_mut()
1279 .extend(bob.send(tag_alice, b"Hi Alice! I think we are!").unwrap());
1280 messages_alice
1281 .borrow_mut()
1282 .extend(bob.send(tag_alice, b"KTHXBYE!").unwrap());
1283 assert!(matches!(
1284 bob.end(tag_alice),
1285 Ok(UserMessage::Reset(tag)) if tag == tag_alice
1286 ));
1287 assert!(matches!(
1288 bob.status(tag_alice),
1289 Some(ProtocolStatus::Plaintext)
1290 ));
1291 assert!(matches!(
1292 handle_messages("Alice", &mut messages_alice, alice),
1293 Some(UserMessage::Confidential(_, _, _))
1294 ));
1295 assert!(matches!(
1296 handle_messages("Alice", &mut messages_alice, alice),
1297 Some(UserMessage::Confidential(_, _, _))
1298 ));
1299 assert!(matches!(
1300 handle_messages("Alice", &mut messages_alice, alice),
1301 Some(UserMessage::ConfidentialSessionFinished(_, _))
1302 ));
1303 assert_eq!(Some(ProtocolStatus::Finished), alice.status(tag_bob));
1304 assert!(matches!(
1305 alice.send(tag_bob, b"Hey, wait up!!!"),
1306 Err(OTRError::IncorrectState(_))
1307 ));
1308 assert!(matches!(
1309 alice.end(tag_bob),
1310 Ok(UserMessage::Reset(tag)) if tag == tag_bob
1311 ));
1312 assert!(matches!(
1313 alice.status(tag_bob),
1314 Some(ProtocolStatus::Plaintext)
1315 ));
1316 assert!(messages_bob.borrow().is_empty());
1317 assert!(messages_alice.borrow().is_empty());
1318 }
1319
1320 #[test]
1321 fn test_my_first_otr4_session() {
1322 init();
1323 let mut messages_alice: Rc<RefCell<VecDeque<Vec<u8>>>> =
1329 Rc::new(RefCell::new(VecDeque::new()));
1330 let mut messages_bob: Rc<RefCell<VecDeque<Vec<u8>>>> =
1331 Rc::new(RefCell::new(VecDeque::new()));
1332 let mut account_alice = Account::new(
1333 Vec::from("alice"),
1334 Policy::ALLOW_V4,
1335 Rc::new(TestHost(
1336 Rc::clone(&messages_bob),
1337 dsa::Keypair::generate(),
1338 usize::MAX,
1339 ed448::EdDSAKeyPair::generate(),
1340 ed448::EdDSAKeyPair::generate(),
1341 RefCell::new(Vec::new()),
1342 )),
1343 )
1344 .unwrap();
1345 let alice = account_alice.session(b"bob");
1346 let mut account_bob = Account::new(
1347 Vec::from("bob"),
1348 Policy::ALLOW_V4,
1349 Rc::new(TestHost(
1350 Rc::clone(&messages_alice),
1351 dsa::Keypair::generate(),
1352 usize::MAX,
1353 ed448::EdDSAKeyPair::generate(),
1354 ed448::EdDSAKeyPair::generate(),
1355 RefCell::new(Vec::new()),
1356 )),
1357 )
1358 .unwrap();
1359 let bob = account_bob.session(b"alice");
1360
1361 alice.query().unwrap();
1362 assert!(handle_messages("Alice", &mut messages_alice, alice).is_none());
1363 assert!(handle_messages("Bob", &mut messages_bob, bob).is_none());
1364 assert!(handle_messages("Alice", &mut messages_alice, alice).is_none());
1365 let result = handle_messages("Bob", &mut messages_bob, bob);
1366 let Some(UserMessage::ConfidentialSessionStarted(tag_alice)) = result else {
1367 panic!("BUG: expected confidential session to have started now.")
1368 };
1369 assert_eq!(Some(ProtocolStatus::Encrypted), bob.status(tag_alice));
1370 let result = handle_messages("Alice", &mut messages_alice, alice).unwrap();
1371 let UserMessage::ConfidentialSessionStarted(tag_bob) = result else {
1372 panic!("BUG: expected confidential session to have started now.")
1373 };
1374 assert_eq!(Some(ProtocolStatus::Encrypted), alice.status(tag_bob));
1375 messages_bob.borrow_mut().extend(
1376 alice
1377 .send(tag_bob, b"Hello Bob! Are we chatting confidentially now?")
1378 .unwrap(),
1379 );
1380 assert!(matches!(
1381 handle_messages("Bob", &mut messages_bob, bob),
1382 Some(UserMessage::Confidential(_, _, _))
1383 ));
1384 messages_alice
1385 .borrow_mut()
1386 .extend(bob.send(tag_alice, b"Hi Alice! I think we are!").unwrap());
1387 messages_alice
1388 .borrow_mut()
1389 .extend(bob.send(tag_alice, b"KTHXBYE!").unwrap());
1390 assert!(matches!(
1391 bob.end(tag_alice),
1392 Ok(UserMessage::Reset(tag)) if tag == tag_alice
1393 ));
1394 assert!(matches!(
1395 bob.status(tag_alice),
1396 Some(ProtocolStatus::Plaintext)
1397 ));
1398 assert!(matches!(
1399 handle_messages("Alice", &mut messages_alice, alice),
1400 Some(UserMessage::Confidential(_, _, _))
1401 ));
1402 assert!(matches!(
1403 handle_messages("Alice", &mut messages_alice, alice),
1404 Some(UserMessage::Confidential(_, _, _))
1405 ));
1406 assert!(matches!(
1407 handle_messages("Alice", &mut messages_alice, alice),
1408 Some(UserMessage::ConfidentialSessionFinished(_, _))
1409 ));
1410 assert_eq!(Some(ProtocolStatus::Finished), alice.status(tag_bob));
1411 assert!(matches!(
1412 alice.send(tag_bob, b"Hey, wait up!!!"),
1413 Err(OTRError::IncorrectState(_))
1414 ));
1415 assert!(matches!(
1416 alice.end(tag_bob),
1417 Ok(UserMessage::Reset(tag)) if tag == tag_bob
1418 ));
1419 assert!(matches!(
1420 alice.status(tag_bob),
1421 Some(ProtocolStatus::Plaintext)
1422 ));
1423 assert!(messages_bob.borrow().is_empty());
1424 assert!(messages_alice.borrow().is_empty());
1425 }
1426
1427 #[test]
1428 fn test_fragmented_otr_session() {
1429 init();
1430 let mut messages_alice: Rc<RefCell<VecDeque<Vec<u8>>>> =
1438 Rc::new(RefCell::new(VecDeque::new()));
1439 let mut messages_bob: Rc<RefCell<VecDeque<Vec<u8>>>> =
1440 Rc::new(RefCell::new(VecDeque::new()));
1441 let mut account_alice = Account::new(
1442 Vec::from("alice"),
1443 Policy::ALLOW_V3,
1444 Rc::new(TestHost(
1445 Rc::clone(&messages_bob),
1446 dsa::Keypair::generate(),
1447 50,
1448 ed448::EdDSAKeyPair::generate(),
1449 ed448::EdDSAKeyPair::generate(),
1450 RefCell::new(Vec::new()),
1451 )),
1452 )
1453 .unwrap();
1454 let alice = account_alice.session(b"bob");
1455 let mut account_bob = Account::new(
1456 Vec::from("bob"),
1457 Policy::ALLOW_V3,
1458 Rc::new(TestHost(
1459 Rc::clone(&messages_alice),
1460 dsa::Keypair::generate(),
1461 55,
1462 ed448::EdDSAKeyPair::generate(),
1463 ed448::EdDSAKeyPair::generate(),
1464 RefCell::new(Vec::new()),
1465 )),
1466 )
1467 .unwrap();
1468 let bob = account_bob.session(b"alice");
1469
1470 alice.query().unwrap();
1471 assert!(handle_messages("Alice", &mut messages_alice, alice).is_none());
1472 assert!(handle_messages("Bob", &mut messages_bob, bob).is_none());
1473 assert!(handle_messages("Alice", &mut messages_alice, alice).is_none());
1474 assert!(handle_messages("Bob", &mut messages_bob, bob).is_none());
1475 let result = handle_messages("Alice", &mut messages_alice, alice).unwrap();
1476 let UserMessage::ConfidentialSessionStarted(tag_bob) = result else {
1477 panic!("BUG: expected confidential session to have started now.")
1478 };
1479 assert_eq!(Some(ProtocolStatus::Encrypted), alice.status(tag_bob));
1480 messages_bob.borrow_mut().extend(
1481 alice
1482 .send(tag_bob, b"Hello Bob! Are we chatting confidentially now?")
1483 .unwrap(),
1484 );
1485 let result = handle_messages("Bob", &mut messages_bob, bob).unwrap();
1486 let UserMessage::ConfidentialSessionStarted(tag_alice) = result else {
1487 panic!("BUG: expected confidential session to have started now.")
1488 };
1489 assert_eq!(Some(ProtocolStatus::Encrypted), bob.status(tag_alice));
1490 assert!(matches!(
1491 handle_messages("Bob", &mut messages_bob, bob),
1492 Some(UserMessage::Confidential(_, _, _))
1493 ));
1494 messages_alice
1495 .borrow_mut()
1496 .extend(bob.send(tag_alice, b"Hi Alice! I think we are!").unwrap());
1497 messages_alice
1498 .borrow_mut()
1499 .extend(bob.send(tag_alice, b"KTHXBYE!").unwrap());
1500 assert!(matches!(
1501 bob.end(tag_alice),
1502 Ok(UserMessage::Reset(tag)) if tag == tag_alice
1503 ));
1504 assert!(matches!(
1505 bob.status(tag_alice),
1506 Some(ProtocolStatus::Plaintext)
1507 ));
1508 assert!(matches!(
1509 handle_messages("Alice", &mut messages_alice, alice),
1510 Some(UserMessage::Confidential(_, _, _))
1511 ));
1512 assert!(matches!(
1513 handle_messages("Alice", &mut messages_alice, alice),
1514 Some(UserMessage::Confidential(_, _, _))
1515 ));
1516 assert!(matches!(
1517 handle_messages("Alice", &mut messages_alice, alice),
1518 Some(UserMessage::ConfidentialSessionFinished(_, _))
1519 ));
1520 assert_eq!(Some(ProtocolStatus::Finished), alice.status(tag_bob));
1521 assert!(matches!(
1522 alice.send(tag_bob, b"Hey, wait up!!!"),
1523 Err(OTRError::IncorrectState(_))
1524 ));
1525 assert!(matches!(
1526 alice.end(tag_bob),
1527 Ok(UserMessage::Reset(tag)) if tag == tag_bob
1528 ));
1529 assert!(matches!(
1530 alice.status(tag_bob),
1531 Some(ProtocolStatus::Plaintext)
1532 ));
1533 assert!(messages_bob.borrow().is_empty());
1534 assert!(messages_alice.borrow().is_empty());
1535 }
1536
1537 struct TestHost(
1538 Rc<RefCell<VecDeque<Vec<u8>>>>,
1539 dsa::Keypair,
1540 usize,
1541 ed448::EdDSAKeyPair,
1542 ed448::EdDSAKeyPair,
1543 RefCell<Vec<u8>>,
1544 );
1545
1546 impl Host for TestHost {
1547 fn message_size(&self) -> usize {
1548 self.2
1549 }
1550
1551 fn inject(&self, _address: &[u8], message: &[u8]) {
1552 self.0.borrow_mut().push_back(Vec::from(message));
1553 }
1554
1555 fn keypair(&self) -> Option<&dsa::Keypair> {
1556 Some(&self.1)
1557 }
1558
1559 fn keypair_identity(&self) -> &crate::crypto::ed448::EdDSAKeyPair {
1560 &self.3
1561 }
1562
1563 fn keypair_forging(&self) -> &crate::crypto::ed448::EdDSAKeyPair {
1564 &self.4
1565 }
1566
1567 fn query_smp_secret(&self, _question: &[u8]) -> Option<Vec<u8>> {
1568 Some(b"Password!".to_vec())
1569 }
1570
1571 fn client_profile(&self) -> Vec<u8> {
1572 self.5.borrow().clone()
1573 }
1574
1575 fn update_client_profile(&self, encoded_payload: Vec<u8>) {
1576 self.5.replace(encoded_payload);
1577 }
1578 }
1579
1580 fn handle_messages(
1581 id: &str,
1582 channel: &mut Rc<RefCell<VecDeque<Vec<u8>>>>,
1583 session: &mut Session,
1584 ) -> Option<UserMessage> {
1585 println!("Messages available: {}", channel.borrow_mut().len());
1586 while let Some(m) = channel.borrow_mut().pop_front() {
1587 println!(
1588 "{}: processing message `{}`",
1589 id,
1590 core::str::from_utf8(&m).unwrap()
1591 );
1592 let message = session.receive(&m).unwrap();
1593 extract_readable(id, &message);
1594 if let UserMessage::None = message {
1595 } else {
1597 return Some(message);
1598 }
1599 }
1600 None
1601 }
1602
1603 fn extract_readable(id: &str, msg: &UserMessage) {
1604 match msg {
1605 UserMessage::None => println!("{id}: (none)"),
1606 UserMessage::Plaintext(msg) => {
1607 println!("{id}: {}", core::str::from_utf8(msg).unwrap());
1608 }
1609 UserMessage::ConfidentialSessionStarted(tag) => {
1610 println!("{id}: confidential session started for instance {tag}");
1611 }
1612 UserMessage::Confidential(tag, message, tlvs) => println!(
1613 "{id}: confidential message on {tag}: {} (TLVs: {tlvs:?})",
1614 core::str::from_utf8(message).unwrap(),
1615 ),
1616 UserMessage::ConfidentialSessionFinished(tag, content) => {
1617 println!(
1618 "{id}: confidential session finished for instance {tag} (\"{}\")",
1619 core::str::from_utf8(content).unwrap()
1620 );
1621 }
1622 UserMessage::WarningUnencrypted(content) => {
1623 println!(
1624 "{id} WARNING: unencrypted message: {})",
1625 core::str::from_utf8(content).unwrap()
1626 );
1627 }
1628 msg => todo!(
1629 "{}: [test utils: extract_readable]: To be implemented: {:?}",
1630 id,
1631 msg
1632 ),
1633 }
1634 }
1635}