1use std::io::{self, Read, Write};
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use uuid::Uuid;
5
6use super::{CHECKSUM_SCHEME_RFC3961, NEGOEXTS_MESSAGE_SIGNATURE, NegoexDataType};
7
8const GUID_SIZE: usize = 16;
9pub(crate) const CHECKSUM_HEADER_LEN: u32 = 4 + 4 + 4 + 8 ;
10
11pub type Guid = Uuid;
12
13impl NegoexDataType for Guid {
14 type Error = io::Error;
15
16 fn size(&self) -> usize {
17 GUID_SIZE
18 }
19
20 fn decode(mut from: impl Read, _message: &[u8]) -> Result<Self, Self::Error> {
21 let mut id_bytes = [0; GUID_SIZE];
22 from.read_exact(&mut id_bytes)?;
23
24 Ok(Self::from_bytes_le(id_bytes))
25 }
26
27 fn encode_with_payload(&self, _offset: usize, mut to: impl Write, _data: impl Write) -> Result<usize, Self::Error> {
28 to.write_all(&self.to_bytes_le())?;
29
30 Ok(0)
31 }
32
33 fn encode(&self, to: impl Write) -> Result<(), Self::Error> {
34 self.encode_with_payload(0, to, &mut [] as &mut [u8])?;
35
36 Ok(())
37 }
38}
39
40pub type ConversationId = Guid;
45
46pub type AuthScheme = Guid;
51
52const MESSAGE_TYPE_SIZE: usize = 4;
54
55#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum MessageType {
71 InitiatorNego,
72 AcceptorNego,
73 InitiatorMetaData,
74 AcceptorMetaData,
75 Challenge,
76 ApRequest,
77 Verify,
78 Alert,
79}
80
81impl NegoexDataType for MessageType {
82 type Error = io::Error;
83
84 fn size(&self) -> usize {
85 MESSAGE_TYPE_SIZE
86 }
87
88 fn decode(mut from: impl Read, _message: &[u8]) -> Result<Self, Self::Error> {
89 MessageType::try_from(from.read_u32::<LittleEndian>()?)
90 }
91
92 fn encode_with_payload(&self, _offset: usize, mut to: impl Write, _data: impl Write) -> Result<usize, Self::Error> {
93 to.write_u32::<LittleEndian>(self.into())?;
94
95 Ok(0)
96 }
97
98 fn encode(&self, to: impl Write) -> Result<(), Self::Error> {
99 self.encode_with_payload(0, to, &mut [] as &mut [u8])?;
100
101 Ok(())
102 }
103}
104
105impl TryFrom<u32> for MessageType {
106 type Error = io::Error;
107
108 fn try_from(type_raw: u32) -> Result<Self, Self::Error> {
109 match type_raw {
110 0 => Ok(MessageType::InitiatorNego),
111 1 => Ok(MessageType::AcceptorNego),
112 2 => Ok(MessageType::InitiatorMetaData),
113 3 => Ok(MessageType::AcceptorMetaData),
114 4 => Ok(MessageType::Challenge),
115 5 => Ok(MessageType::ApRequest),
116 6 => Ok(MessageType::Verify),
117 7 => Ok(MessageType::Alert),
118 _ => Err(io::Error::new(io::ErrorKind::InvalidData, "invalid MessageType")),
119 }
120 }
121}
122
123impl From<&MessageType> for u32 {
124 fn from(message_type: &MessageType) -> Self {
125 match message_type {
126 MessageType::InitiatorNego => 0,
127 MessageType::AcceptorNego => 1,
128 MessageType::InitiatorMetaData => 2,
129 MessageType::AcceptorMetaData => 3,
130 MessageType::Challenge => 4,
131 MessageType::ApRequest => 5,
132 MessageType::Verify => 6,
133 MessageType::Alert => 7,
134 }
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
151pub struct MessageHeader {
152 pub signature: u64,
153 pub message_type: MessageType,
154 pub sequence_num: u32,
155 pub header_len: u32,
156 pub message_len: u32,
157 pub conversation_id: ConversationId,
158}
159
160impl NegoexDataType for MessageHeader {
161 type Error = io::Error;
162
163 fn size(&self) -> usize {
164 8 +
165 self.message_type.size() +
166 4 +
167 4 +
168 4 +
169 self.conversation_id.size()
170 }
171
172 fn decode(mut from: impl Read, message: &[u8]) -> Result<Self, Self::Error> {
173 let signature = from.read_u64::<LittleEndian>()?;
174
175 if signature != NEGOEXTS_MESSAGE_SIGNATURE {
176 return Err(io::Error::new(
177 io::ErrorKind::InvalidData,
178 format!("invalid message signature: {signature:x?}. expected: {NEGOEXTS_MESSAGE_SIGNATURE:x?}"),
179 ));
180 }
181
182 let message_type = MessageType::decode(&mut from, message)?;
183
184 let sequence_num = from.read_u32::<LittleEndian>()?;
185
186 let header_len = from.read_u32::<LittleEndian>()?;
187
188 let message_len = from.read_u32::<LittleEndian>()?;
189
190 let conversation_id = ConversationId::decode(&mut from, message)?;
191
192 Ok(Self {
193 signature,
194 message_type,
195 sequence_num,
196 header_len,
197 message_len,
198 conversation_id,
199 })
200 }
201
202 fn encode_with_payload(
203 &self,
204 offset: usize,
205 mut to: impl Write,
206 mut data: impl Write,
207 ) -> Result<usize, Self::Error> {
208 to.write_u64::<LittleEndian>(self.signature)?;
209
210 let message_type_offset = self.message_type.encode_with_payload(offset, &mut to, &mut data)?;
211
212 to.write_u32::<LittleEndian>(self.sequence_num)?;
213
214 to.write_u32::<LittleEndian>(self.header_len)?;
215
216 to.write_u32::<LittleEndian>(self.message_len)?;
217
218 let conversation_id_offset = self.conversation_id.encode_with_payload(offset, &mut to, &mut data)?;
219
220 Ok(message_type_offset + conversation_id_offset)
221 }
222
223 fn encode(&self, to: impl Write) -> Result<(), Self::Error> {
224 self.encode_with_payload(0, to, &mut [] as &mut [u8])?;
225
226 Ok(())
227 }
228}
229
230#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct Extension {
240 pub extension_type: u32,
241 pub extension_value: ByteVector,
242}
243
244impl NegoexDataType for Extension {
245 type Error = io::Error;
246
247 fn size(&self) -> usize {
248 4 + self.extension_value.len()
249 }
250
251 fn decode(mut from: impl Read, message: &[u8]) -> Result<Self, Self::Error> {
252 let extension_type = from.read_u32::<LittleEndian>()?;
253
254 let extension_value = ByteVector::decode(&mut from, message)?;
255
256 Ok(Self {
257 extension_type,
258 extension_value,
259 })
260 }
261
262 fn encode_with_payload(
263 &self,
264 offset: usize,
265 mut to: impl Write,
266 mut data: impl Write,
267 ) -> Result<usize, Self::Error> {
268 to.write_u32::<LittleEndian>(self.extension_type)?;
269
270 self.extension_value.encode_with_payload(offset, &mut to, &mut data)
271 }
272
273 fn encode(&self, mut to: impl Write) -> Result<(), Self::Error> {
274 let offset = 12;
275
276 let mut header = Vec::new();
277 let mut data = Vec::new();
278
279 self.encode_with_payload(offset, &mut header, &mut data)?;
280
281 to.write_all(&header)?;
282 to.write_all(&data)?;
283
284 Ok(())
285 }
286}
287
288pub type ByteVector = Vec<u8>;
297
298pub type AuthSchemeVector = Vec<AuthScheme>;
307
308pub type ExtensionVector = Vec<Extension>;
317
318#[derive(Debug, Clone, PartialEq, Eq)]
329pub struct Checksum {
330 pub header_len: u32,
331 pub checksum_scheme: u32,
332 pub checksum_type: u32,
333 pub checksum_value: Vec<u8>,
334}
335
336impl NegoexDataType for Checksum {
337 type Error = io::Error;
338
339 fn size(&self) -> usize {
340 4 +
341 4 +
342 4 +
343 4 +
344 self.checksum_value.size()
345 }
346
347 fn decode(mut from: impl Read, message: &[u8]) -> Result<Self, Self::Error> {
348 let header_len = from.read_u32::<LittleEndian>()?;
349
350 let checksum_scheme = from.read_u32::<LittleEndian>()?;
351
352 if checksum_scheme != CHECKSUM_SCHEME_RFC3961 {
353 return Err(io::Error::new(
354 io::ErrorKind::InvalidInput,
355 format!("invalid checksum scheme: {checksum_scheme}. Expected: {CHECKSUM_SCHEME_RFC3961}"),
356 ));
357 }
358
359 let checksum_type = from.read_u32::<LittleEndian>()?;
360
361 let checksum_value = Vec::decode(&mut from, message)?;
362
363 Ok(Self {
364 header_len,
365 checksum_scheme,
366 checksum_type,
367 checksum_value,
368 })
369 }
370
371 fn encode_with_payload(
372 &self,
373 offset: usize,
374 mut to: impl Write,
375 mut data: impl Write,
376 ) -> Result<usize, Self::Error> {
377 to.write_u32::<LittleEndian>(self.header_len)?;
378
379 to.write_u32::<LittleEndian>(self.checksum_scheme)?;
380
381 to.write_u32::<LittleEndian>(self.checksum_type)?;
382
383 self.checksum_value.encode_with_payload(offset, &mut to, &mut data)
384 }
385
386 fn encode(&self, mut to: impl Write) -> Result<(), Self::Error> {
387 let offset = self.header_len as usize;
388
389 let mut header = Vec::new();
390 let mut data = Vec::new();
391
392 self.encode_with_payload(offset, &mut header, &mut data)?;
393
394 to.write_all(&header)?;
395 to.write_all(&data)?;
396
397 Ok(())
398 }
399}
400
401#[cfg(test)]
402mod tests {
403 use std::str::FromStr;
404
405 use uuid::Uuid;
406
407 use crate::constants::cksum_types::HMAC_SHA1_96_AES256;
408 use crate::negoex::NegoexDataType;
409 use crate::negoex::data_types::Guid;
410
411 use super::{CHECKSUM_SCHEME_RFC3961, Checksum, Extension, MessageHeader, MessageType, NEGOEXTS_MESSAGE_SIGNATURE};
412
413 #[test]
414 fn guid_encode() {
415 let guid = Uuid::from_str("0d53335c-f9ea-4d0d-b2ec-4ae3786ec308").unwrap();
416
417 let mut encoded = Vec::new();
418 guid.encode(&mut encoded).unwrap();
419
420 assert_eq!(
421 &[92, 51, 83, 13, 234, 249, 13, 77, 178, 236, 74, 227, 120, 110, 195, 8],
422 encoded.as_slice()
423 );
424 }
425
426 #[test]
427 fn guid_decode() {
428 let encoded_guid = [90, 7, 41, 59, 145, 243, 51, 175, 161, 180, 162, 18, 36, 157, 124, 180];
429
430 let guid = Guid::decode(&encoded_guid as &[u8], &encoded_guid).unwrap();
431
432 assert_eq!(Uuid::from_str("3b29075a-f391-af33-a1b4-a212249d7cb4").unwrap(), guid);
433 }
434
435 #[test]
436 fn message_type_decode() {
437 let encoded = [1, 0, 0, 0];
438
439 let message_type = MessageType::decode(&encoded as &[u8], &encoded).unwrap();
440
441 assert_eq!(MessageType::AcceptorNego, message_type);
442 }
443
444 #[test]
445 fn message_type_encode() {
446 let message_type = MessageType::ApRequest;
447
448 let mut encoded = Vec::new();
449 message_type.encode(&mut encoded).unwrap();
450
451 assert_eq!(&[5, 0, 0, 0], encoded.as_slice());
452 }
453
454 #[test]
455 fn message_header_encode() {
456 let message_header = MessageHeader {
457 signature: NEGOEXTS_MESSAGE_SIGNATURE,
458 message_type: MessageType::AcceptorNego,
459 sequence_num: 2,
460 header_len: 96,
461 message_len: 112,
462 conversation_id: Guid::from_str("3b29075a-f391-af33-a1b4-a212249d7cb4").unwrap(),
463 };
464
465 let mut encoded = Vec::new();
466 message_header.encode(&mut encoded).unwrap();
467
468 assert_eq!(
469 &[
470 78, 69, 71, 79, 69, 88, 84, 83, 1, 0, 0, 0, 2, 0, 0, 0, 96, 0, 0, 0, 112, 0, 0, 0, 90, 7, 41, 59, 145,
471 243, 51, 175, 161, 180, 162, 18, 36, 157, 124, 180
472 ],
473 encoded.as_slice(),
474 );
475 }
476
477 #[test]
478 fn message_header_decode() {
479 let encoded = [
480 78, 69, 71, 79, 69, 88, 84, 83, 1, 0, 0, 0, 2, 0, 0, 0, 96, 0, 0, 0, 112, 0, 0, 0, 90, 7, 41, 59, 145, 243,
481 51, 175, 161, 180, 162, 18, 36, 157, 124, 180,
482 ];
483
484 let message_header = MessageHeader::decode(&encoded as &[u8], &encoded).unwrap();
485
486 assert_eq!(
487 MessageHeader {
488 signature: NEGOEXTS_MESSAGE_SIGNATURE,
489 message_type: MessageType::AcceptorNego,
490 sequence_num: 2,
491 header_len: 96,
492 message_len: 112,
493 conversation_id: Guid::from_str("3b29075a-f391-af33-a1b4-a212249d7cb4").unwrap(),
494 },
495 message_header,
496 );
497 }
498
499 #[test]
500 fn extension_encode() {
501 let extension = Extension {
502 extension_type: 3,
503 extension_value: vec![1, 2, 3, 4, 5, 6],
504 };
505
506 let mut encoded = Vec::new();
507 extension.encode(&mut encoded).unwrap();
508
509 assert_eq!(
510 &[3, 0, 0, 0, 12, 0, 0, 0, 6, 0, 0, 0, 1, 2, 3, 4, 5, 6],
511 encoded.as_slice()
512 );
513 }
514
515 #[test]
516 fn extension_decode() {
517 let encoded = [3, 0, 0, 0, 12, 0, 0, 0, 6, 0, 0, 0, 1, 2, 3, 4, 5, 6];
518
519 let extension = Extension::decode(&encoded as &[u8], &encoded).unwrap();
520
521 assert_eq!(
522 Extension {
523 extension_type: 3,
524 extension_value: vec![1, 2, 3, 4, 5, 6],
525 },
526 extension
527 );
528 }
529
530 #[test]
531 fn checksum_decode() {
532 let negoex_verify = [
534 78, 69, 71, 79, 69, 88, 84, 83, 6, 0, 0, 0, 7, 0, 0, 0, 80, 0, 0, 0, 92, 0, 0, 0, 90, 7, 41, 59, 145, 243,
535 51, 175, 161, 180, 162, 18, 36, 157, 124, 180, 92, 51, 83, 13, 234, 249, 13, 77, 178, 236, 74, 227, 120,
536 110, 195, 8, 20, 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 80, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 228, 167, 112,
537 148, 23, 131, 204, 12, 13, 36, 58, 87,
538 ];
539
540 let checksum = Checksum::decode(&negoex_verify[56..], &negoex_verify).unwrap();
542
543 assert_eq!(
544 Checksum {
545 header_len: 20,
546 checksum_scheme: CHECKSUM_SCHEME_RFC3961,
547 checksum_type: HMAC_SHA1_96_AES256 as u32,
548 checksum_value: vec![228, 167, 112, 148, 23, 131, 204, 12, 13, 36, 58, 87],
549 },
550 checksum
551 );
552 }
553
554 #[test]
555 fn checksum_encode() {
556 let checksum = Checksum {
557 header_len: 20,
558 checksum_scheme: CHECKSUM_SCHEME_RFC3961,
559 checksum_type: HMAC_SHA1_96_AES256 as u32,
560 checksum_value: vec![228, 167, 112, 148, 23, 131, 204, 12, 13, 36, 58, 87],
561 };
562
563 let mut encoded = Vec::new();
564 checksum.encode(&mut encoded).unwrap();
565
566 assert_eq!(
567 &[
568 20, 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 20, 0, 0, 0, 12, 0, 0, 0, 228, 167, 112, 148, 23, 131, 204, 12,
569 13, 36, 58, 87
570 ],
571 encoded.as_slice(),
572 )
573 }
574}