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!(
179 "invalid message signature: {:x?}. expected: {:x?}",
180 signature, NEGOEXTS_MESSAGE_SIGNATURE
181 ),
182 ));
183 }
184
185 let message_type = MessageType::decode(&mut from, message)?;
186
187 let sequence_num = from.read_u32::<LittleEndian>()?;
188
189 let header_len = from.read_u32::<LittleEndian>()?;
190
191 let message_len = from.read_u32::<LittleEndian>()?;
192
193 let conversation_id = ConversationId::decode(&mut from, message)?;
194
195 Ok(Self {
196 signature,
197 message_type,
198 sequence_num,
199 header_len,
200 message_len,
201 conversation_id,
202 })
203 }
204
205 fn encode_with_payload(
206 &self,
207 offset: usize,
208 mut to: impl Write,
209 mut data: impl Write,
210 ) -> Result<usize, Self::Error> {
211 to.write_u64::<LittleEndian>(self.signature)?;
212
213 let message_type_offset = self.message_type.encode_with_payload(offset, &mut to, &mut data)?;
214
215 to.write_u32::<LittleEndian>(self.sequence_num)?;
216
217 to.write_u32::<LittleEndian>(self.header_len)?;
218
219 to.write_u32::<LittleEndian>(self.message_len)?;
220
221 let conversation_id_offset = self.conversation_id.encode_with_payload(offset, &mut to, &mut data)?;
222
223 Ok(message_type_offset + conversation_id_offset)
224 }
225
226 fn encode(&self, to: impl Write) -> Result<(), Self::Error> {
227 self.encode_with_payload(0, to, &mut [] as &mut [u8])?;
228
229 Ok(())
230 }
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
242pub struct Extension {
243 pub extension_type: u32,
244 pub extension_value: ByteVector,
245}
246
247impl NegoexDataType for Extension {
248 type Error = io::Error;
249
250 fn size(&self) -> usize {
251 4 + self.extension_value.len()
252 }
253
254 fn decode(mut from: impl Read, message: &[u8]) -> Result<Self, Self::Error> {
255 let extension_type = from.read_u32::<LittleEndian>()?;
256
257 let extension_value = ByteVector::decode(&mut from, message)?;
258
259 Ok(Self {
260 extension_type,
261 extension_value,
262 })
263 }
264
265 fn encode_with_payload(
266 &self,
267 offset: usize,
268 mut to: impl Write,
269 mut data: impl Write,
270 ) -> Result<usize, Self::Error> {
271 to.write_u32::<LittleEndian>(self.extension_type)?;
272
273 self.extension_value.encode_with_payload(offset, &mut to, &mut data)
274 }
275
276 fn encode(&self, mut to: impl Write) -> Result<(), Self::Error> {
277 let offset = 12;
278
279 let mut header = Vec::new();
280 let mut data = Vec::new();
281
282 self.encode_with_payload(offset, &mut header, &mut data)?;
283
284 to.write_all(&header)?;
285 to.write_all(&data)?;
286
287 Ok(())
288 }
289}
290
291pub type ByteVector = Vec<u8>;
300
301pub type AuthSchemeVector = Vec<AuthScheme>;
310
311pub type ExtensionVector = Vec<Extension>;
320
321#[derive(Debug, Clone, PartialEq, Eq)]
332pub struct Checksum {
333 pub header_len: u32,
334 pub checksum_scheme: u32,
335 pub checksum_type: u32,
336 pub checksum_value: Vec<u8>,
337}
338
339impl NegoexDataType for Checksum {
340 type Error = io::Error;
341
342 fn size(&self) -> usize {
343 4 +
344 4 +
345 4 +
346 4 +
347 self.checksum_value.size()
348 }
349
350 fn decode(mut from: impl Read, message: &[u8]) -> Result<Self, Self::Error> {
351 let header_len = from.read_u32::<LittleEndian>()?;
352
353 let checksum_scheme = from.read_u32::<LittleEndian>()?;
354
355 if checksum_scheme != CHECKSUM_SCHEME_RFC3961 {
356 return Err(io::Error::new(
357 io::ErrorKind::InvalidInput,
358 format!(
359 "invalid checksum scheme: {}. Expected: {}",
360 checksum_scheme, CHECKSUM_SCHEME_RFC3961
361 ),
362 ));
363 }
364
365 let checksum_type = from.read_u32::<LittleEndian>()?;
366
367 let checksum_value = Vec::decode(&mut from, message)?;
368
369 Ok(Self {
370 header_len,
371 checksum_scheme,
372 checksum_type,
373 checksum_value,
374 })
375 }
376
377 fn encode_with_payload(
378 &self,
379 offset: usize,
380 mut to: impl Write,
381 mut data: impl Write,
382 ) -> Result<usize, Self::Error> {
383 to.write_u32::<LittleEndian>(self.header_len)?;
384
385 to.write_u32::<LittleEndian>(self.checksum_scheme)?;
386
387 to.write_u32::<LittleEndian>(self.checksum_type)?;
388
389 self.checksum_value.encode_with_payload(offset, &mut to, &mut data)
390 }
391
392 fn encode(&self, mut to: impl Write) -> Result<(), Self::Error> {
393 let offset = self.header_len as usize;
394
395 let mut header = Vec::new();
396 let mut data = Vec::new();
397
398 self.encode_with_payload(offset, &mut header, &mut data)?;
399
400 to.write_all(&header)?;
401 to.write_all(&data)?;
402
403 Ok(())
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use std::str::FromStr;
410
411 use uuid::Uuid;
412
413 use crate::constants::cksum_types::HMAC_SHA1_96_AES256;
414 use crate::negoex::NegoexDataType;
415 use crate::negoex::data_types::Guid;
416
417 use super::{CHECKSUM_SCHEME_RFC3961, Checksum, Extension, MessageHeader, MessageType, NEGOEXTS_MESSAGE_SIGNATURE};
418
419 #[test]
420 fn guid_encode() {
421 let guid = Uuid::from_str("0d53335c-f9ea-4d0d-b2ec-4ae3786ec308").unwrap();
422
423 let mut encoded = Vec::new();
424 guid.encode(&mut encoded).unwrap();
425
426 assert_eq!(
427 &[92, 51, 83, 13, 234, 249, 13, 77, 178, 236, 74, 227, 120, 110, 195, 8],
428 encoded.as_slice()
429 );
430 }
431
432 #[test]
433 fn guid_decode() {
434 let encoded_guid = [90, 7, 41, 59, 145, 243, 51, 175, 161, 180, 162, 18, 36, 157, 124, 180];
435
436 let guid = Guid::decode(&encoded_guid as &[u8], &encoded_guid).unwrap();
437
438 assert_eq!(Uuid::from_str("3b29075a-f391-af33-a1b4-a212249d7cb4").unwrap(), guid);
439 }
440
441 #[test]
442 fn message_type_decode() {
443 let encoded = [1, 0, 0, 0];
444
445 let message_type = MessageType::decode(&encoded as &[u8], &encoded).unwrap();
446
447 assert_eq!(MessageType::AcceptorNego, message_type);
448 }
449
450 #[test]
451 fn message_type_encode() {
452 let message_type = MessageType::ApRequest;
453
454 let mut encoded = Vec::new();
455 message_type.encode(&mut encoded).unwrap();
456
457 assert_eq!(&[5, 0, 0, 0], encoded.as_slice());
458 }
459
460 #[test]
461 fn message_header_encode() {
462 let message_header = MessageHeader {
463 signature: NEGOEXTS_MESSAGE_SIGNATURE,
464 message_type: MessageType::AcceptorNego,
465 sequence_num: 2,
466 header_len: 96,
467 message_len: 112,
468 conversation_id: Guid::from_str("3b29075a-f391-af33-a1b4-a212249d7cb4").unwrap(),
469 };
470
471 let mut encoded = Vec::new();
472 message_header.encode(&mut encoded).unwrap();
473
474 assert_eq!(
475 &[
476 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,
477 243, 51, 175, 161, 180, 162, 18, 36, 157, 124, 180
478 ],
479 encoded.as_slice(),
480 );
481 }
482
483 #[test]
484 fn message_header_decode() {
485 let encoded = [
486 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,
487 51, 175, 161, 180, 162, 18, 36, 157, 124, 180,
488 ];
489
490 let message_header = MessageHeader::decode(&encoded as &[u8], &encoded).unwrap();
491
492 assert_eq!(
493 MessageHeader {
494 signature: NEGOEXTS_MESSAGE_SIGNATURE,
495 message_type: MessageType::AcceptorNego,
496 sequence_num: 2,
497 header_len: 96,
498 message_len: 112,
499 conversation_id: Guid::from_str("3b29075a-f391-af33-a1b4-a212249d7cb4").unwrap(),
500 },
501 message_header,
502 );
503 }
504
505 #[test]
506 fn extension_encode() {
507 let extension = Extension {
508 extension_type: 3,
509 extension_value: vec![1, 2, 3, 4, 5, 6],
510 };
511
512 let mut encoded = Vec::new();
513 extension.encode(&mut encoded).unwrap();
514
515 assert_eq!(
516 &[3, 0, 0, 0, 12, 0, 0, 0, 6, 0, 0, 0, 1, 2, 3, 4, 5, 6],
517 encoded.as_slice()
518 );
519 }
520
521 #[test]
522 fn extension_decode() {
523 let encoded = [3, 0, 0, 0, 12, 0, 0, 0, 6, 0, 0, 0, 1, 2, 3, 4, 5, 6];
524
525 let extension = Extension::decode(&encoded as &[u8], &encoded).unwrap();
526
527 assert_eq!(
528 Extension {
529 extension_type: 3,
530 extension_value: vec![1, 2, 3, 4, 5, 6],
531 },
532 extension
533 );
534 }
535
536 #[test]
537 fn checksum_decode() {
538 let negoex_verify = [
540 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,
541 51, 175, 161, 180, 162, 18, 36, 157, 124, 180, 92, 51, 83, 13, 234, 249, 13, 77, 178, 236, 74, 227, 120,
542 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,
543 148, 23, 131, 204, 12, 13, 36, 58, 87,
544 ];
545
546 let checksum = Checksum::decode(&negoex_verify[56..], &negoex_verify).unwrap();
548
549 assert_eq!(
550 Checksum {
551 header_len: 20,
552 checksum_scheme: CHECKSUM_SCHEME_RFC3961,
553 checksum_type: HMAC_SHA1_96_AES256 as u32,
554 checksum_value: vec![228, 167, 112, 148, 23, 131, 204, 12, 13, 36, 58, 87],
555 },
556 checksum
557 );
558 }
559
560 #[test]
561 fn checksum_encode() {
562 let checksum = Checksum {
563 header_len: 20,
564 checksum_scheme: CHECKSUM_SCHEME_RFC3961,
565 checksum_type: HMAC_SHA1_96_AES256 as u32,
566 checksum_value: vec![228, 167, 112, 148, 23, 131, 204, 12, 13, 36, 58, 87],
567 };
568
569 let mut encoded = Vec::new();
570 checksum.encode(&mut encoded).unwrap();
571
572 assert_eq!(
573 &[
574 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,
575 13, 36, 58, 87
576 ],
577 encoded.as_slice(),
578 )
579 }
580}