1use crate::ber::{Decoder, EncodeBuf};
23use crate::error::{DecodeErrorKind, Error, Result};
24use crate::pdu::Pdu;
25use bytes::Bytes;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29#[repr(i32)]
30pub enum SecurityModel {
31 Usm = 3,
33}
34
35impl SecurityModel {
36 pub fn from_i32(value: i32) -> Option<Self> {
38 match value {
39 3 => Some(Self::Usm),
40 _ => None,
41 }
42 }
43
44 pub fn as_i32(self) -> i32 {
46 self as i32
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
55pub enum SecurityLevel {
56 NoAuthNoPriv,
58 AuthNoPriv,
60 AuthPriv,
62}
63
64impl SecurityLevel {
65 pub fn from_flags(flags: u8) -> Option<Self> {
67 let auth = flags & 0x01 != 0;
68 let priv_ = flags & 0x02 != 0;
69
70 match (auth, priv_) {
71 (false, false) => Some(Self::NoAuthNoPriv),
72 (true, false) => Some(Self::AuthNoPriv),
73 (true, true) => Some(Self::AuthPriv),
74 (false, true) => None, }
76 }
77
78 pub fn to_flags(self) -> u8 {
80 match self {
81 Self::NoAuthNoPriv => 0x00,
82 Self::AuthNoPriv => 0x01,
83 Self::AuthPriv => 0x03,
84 }
85 }
86
87 pub fn requires_auth(self) -> bool {
89 matches!(self, Self::AuthNoPriv | Self::AuthPriv)
90 }
91
92 pub fn requires_priv(self) -> bool {
94 matches!(self, Self::AuthPriv)
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub struct MsgFlags {
101 pub security_level: SecurityLevel,
103 pub reportable: bool,
105}
106
107impl MsgFlags {
108 pub fn new(security_level: SecurityLevel, reportable: bool) -> Self {
110 Self {
111 security_level,
112 reportable,
113 }
114 }
115
116 pub fn from_byte(byte: u8) -> Result<Self> {
118 let security_level = SecurityLevel::from_flags(byte)
119 .ok_or_else(|| Error::decode(0, DecodeErrorKind::InvalidMsgFlags))?;
120 let reportable = byte & 0x04 != 0;
121 Ok(Self {
122 security_level,
123 reportable,
124 })
125 }
126
127 pub fn to_byte(self) -> u8 {
129 let mut flags = self.security_level.to_flags();
130 if self.reportable {
131 flags |= 0x04;
132 }
133 flags
134 }
135}
136
137#[derive(Debug, Clone)]
139pub struct MsgGlobalData {
140 pub msg_id: i32,
142 pub msg_max_size: i32,
144 pub msg_flags: MsgFlags,
146 pub msg_security_model: SecurityModel,
148}
149
150impl MsgGlobalData {
151 pub fn new(msg_id: i32, msg_max_size: i32, msg_flags: MsgFlags) -> Self {
153 Self {
154 msg_id,
155 msg_max_size,
156 msg_flags,
157 msg_security_model: SecurityModel::Usm,
158 }
159 }
160
161 pub fn encode(&self, buf: &mut EncodeBuf) {
163 buf.push_sequence(|buf| {
164 buf.push_integer(self.msg_security_model.as_i32());
165 buf.push_octet_string(&[self.msg_flags.to_byte()]);
167 buf.push_integer(self.msg_max_size);
168 buf.push_integer(self.msg_id);
169 });
170 }
171
172 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
179 const MSG_MAX_SIZE_MINIMUM: i32 = 484;
180
181 let mut seq = decoder.read_sequence()?;
182
183 let msg_id = seq.read_integer()?;
184 let msg_max_size = seq.read_integer()?;
185
186 if msg_id < 0 {
188 return Err(Error::decode(
189 seq.offset(),
190 DecodeErrorKind::InvalidMsgId { value: msg_id },
191 ));
192 }
193
194 if msg_max_size < 0 {
197 return Err(Error::decode(
198 seq.offset(),
199 DecodeErrorKind::MsgMaxSizeTooLarge {
200 value: msg_max_size,
201 },
202 ));
203 }
204
205 if msg_max_size < MSG_MAX_SIZE_MINIMUM {
206 return Err(Error::decode(
207 seq.offset(),
208 DecodeErrorKind::MsgMaxSizeTooSmall {
209 value: msg_max_size,
210 minimum: MSG_MAX_SIZE_MINIMUM,
211 },
212 ));
213 }
214
215 let flags_bytes = seq.read_octet_string()?;
216 if flags_bytes.len() != 1 {
217 return Err(Error::decode(
218 seq.offset(),
219 DecodeErrorKind::UnexpectedTag {
220 expected: 1,
221 actual: flags_bytes.len() as u8,
222 },
223 ));
224 }
225 let msg_flags = MsgFlags::from_byte(flags_bytes[0])?;
226
227 let msg_security_model_raw = seq.read_integer()?;
228 let msg_security_model =
230 SecurityModel::from_i32(msg_security_model_raw).ok_or_else(|| {
231 Error::decode(
232 seq.offset(),
233 DecodeErrorKind::UnknownSecurityModel(msg_security_model_raw),
234 )
235 })?;
236
237 Ok(Self {
238 msg_id,
239 msg_max_size,
240 msg_flags,
241 msg_security_model,
242 })
243 }
244}
245
246#[derive(Debug, Clone)]
248pub struct ScopedPdu {
249 pub context_engine_id: Bytes,
251 pub context_name: Bytes,
253 pub pdu: Pdu,
255}
256
257impl ScopedPdu {
258 pub fn new(
260 context_engine_id: impl Into<Bytes>,
261 context_name: impl Into<Bytes>,
262 pdu: Pdu,
263 ) -> Self {
264 Self {
265 context_engine_id: context_engine_id.into(),
266 context_name: context_name.into(),
267 pdu,
268 }
269 }
270
271 pub fn with_empty_context(pdu: Pdu) -> Self {
273 Self {
274 context_engine_id: Bytes::new(),
275 context_name: Bytes::new(),
276 pdu,
277 }
278 }
279
280 pub fn encode(&self, buf: &mut EncodeBuf) {
282 buf.push_sequence(|buf| {
283 self.pdu.encode(buf);
284 buf.push_octet_string(&self.context_name);
285 buf.push_octet_string(&self.context_engine_id);
286 });
287 }
288
289 pub fn encode_to_bytes(&self) -> Bytes {
291 let mut buf = EncodeBuf::new();
292 self.encode(&mut buf);
293 buf.finish()
294 }
295
296 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
298 let mut seq = decoder.read_sequence()?;
299
300 let context_engine_id = seq.read_octet_string()?;
301 let context_name = seq.read_octet_string()?;
302 let pdu = Pdu::decode(&mut seq)?;
303
304 Ok(Self {
305 context_engine_id,
306 context_name,
307 pdu,
308 })
309 }
310}
311
312#[derive(Debug, Clone)]
314pub struct V3Message {
315 pub global_data: MsgGlobalData,
317 pub security_params: Bytes,
319 pub data: V3MessageData,
321}
322
323#[derive(Debug, Clone)]
325pub enum V3MessageData {
326 Plaintext(ScopedPdu),
328 Encrypted(Bytes),
330}
331
332impl V3Message {
333 pub fn new(global_data: MsgGlobalData, security_params: Bytes, scoped_pdu: ScopedPdu) -> Self {
335 Self {
336 global_data,
337 security_params,
338 data: V3MessageData::Plaintext(scoped_pdu),
339 }
340 }
341
342 pub fn new_encrypted(
344 global_data: MsgGlobalData,
345 security_params: Bytes,
346 encrypted: Bytes,
347 ) -> Self {
348 Self {
349 global_data,
350 security_params,
351 data: V3MessageData::Encrypted(encrypted),
352 }
353 }
354
355 pub fn scoped_pdu(&self) -> Option<&ScopedPdu> {
357 match &self.data {
358 V3MessageData::Plaintext(pdu) => Some(pdu),
359 V3MessageData::Encrypted(_) => None,
360 }
361 }
362
363 pub fn into_scoped_pdu(self) -> Option<ScopedPdu> {
365 match self.data {
366 V3MessageData::Plaintext(pdu) => Some(pdu),
367 V3MessageData::Encrypted(_) => None,
368 }
369 }
370
371 pub fn pdu(&self) -> Option<&Pdu> {
373 self.scoped_pdu().map(|s| &s.pdu)
374 }
375
376 pub fn into_pdu(self) -> Option<Pdu> {
378 self.into_scoped_pdu().map(|s| s.pdu)
379 }
380
381 pub fn msg_id(&self) -> i32 {
383 self.global_data.msg_id
384 }
385
386 pub fn security_level(&self) -> SecurityLevel {
388 self.global_data.msg_flags.security_level
389 }
390
391 pub fn encode(&self) -> Bytes {
398 let mut buf = EncodeBuf::new();
399
400 buf.push_sequence(|buf| {
401 match &self.data {
403 V3MessageData::Plaintext(scoped_pdu) => {
404 scoped_pdu.encode(buf);
405 }
406 V3MessageData::Encrypted(ciphertext) => {
407 buf.push_octet_string(ciphertext);
408 }
409 }
410
411 buf.push_octet_string(&self.security_params);
413
414 self.global_data.encode(buf);
416
417 buf.push_integer(3);
419 });
420
421 buf.finish()
422 }
423
424 pub fn decode(data: Bytes) -> Result<Self> {
429 let mut decoder = Decoder::new(data);
430 let mut seq = decoder.read_sequence()?;
431
432 let version = seq.read_integer()?;
434 if version != 3 {
435 return Err(Error::decode(
436 seq.offset(),
437 DecodeErrorKind::UnknownVersion(version),
438 ));
439 }
440
441 Self::decode_from_sequence(&mut seq)
442 }
443
444 pub(crate) fn decode_from_sequence(seq: &mut Decoder) -> Result<Self> {
446 let global_data = MsgGlobalData::decode(seq)?;
448
449 let security_params = seq.read_octet_string()?;
451
452 let data = if global_data.msg_flags.security_level.requires_priv() {
454 let encrypted = seq.read_octet_string()?;
456 V3MessageData::Encrypted(encrypted)
457 } else {
458 let scoped_pdu = ScopedPdu::decode(seq)?;
460 V3MessageData::Plaintext(scoped_pdu)
461 };
462
463 Ok(Self {
464 global_data,
465 security_params,
466 data,
467 })
468 }
469
470 pub fn discovery_request(msg_id: i32) -> Self {
475 let global_data = MsgGlobalData::new(
476 msg_id,
477 65507, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true),
479 );
480
481 let security_params = crate::v3::UsmSecurityParams::empty().encode();
483
484 let pdu = Pdu::get_request(0, &[]);
486 let scoped_pdu = ScopedPdu::with_empty_context(pdu);
487
488 Self::new(global_data, security_params, scoped_pdu)
489 }
490}
491
492#[cfg(test)]
493mod tests {
494 use super::*;
495 use crate::oid;
496
497 #[test]
498 fn test_security_level_flags() {
499 assert_eq!(SecurityLevel::NoAuthNoPriv.to_flags(), 0x00);
500 assert_eq!(SecurityLevel::AuthNoPriv.to_flags(), 0x01);
501 assert_eq!(SecurityLevel::AuthPriv.to_flags(), 0x03);
502
503 assert_eq!(
504 SecurityLevel::from_flags(0x00),
505 Some(SecurityLevel::NoAuthNoPriv)
506 );
507 assert_eq!(
508 SecurityLevel::from_flags(0x01),
509 Some(SecurityLevel::AuthNoPriv)
510 );
511 assert_eq!(
512 SecurityLevel::from_flags(0x03),
513 Some(SecurityLevel::AuthPriv)
514 );
515 assert_eq!(SecurityLevel::from_flags(0x02), None); }
517
518 #[test]
519 fn test_msg_flags_roundtrip() {
520 let flags = MsgFlags::new(SecurityLevel::AuthPriv, true);
521 let byte = flags.to_byte();
522 assert_eq!(byte, 0x07); let decoded = MsgFlags::from_byte(byte).unwrap();
525 assert_eq!(decoded.security_level, SecurityLevel::AuthPriv);
526 assert!(decoded.reportable);
527 }
528
529 #[test]
530 fn test_msg_global_data_roundtrip() {
531 let global =
532 MsgGlobalData::new(12345, 1472, MsgFlags::new(SecurityLevel::AuthNoPriv, true));
533
534 let mut buf = EncodeBuf::new();
535 global.encode(&mut buf);
536 let encoded = buf.finish();
537
538 let mut decoder = Decoder::new(encoded);
539 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
540
541 assert_eq!(decoded.msg_id, 12345);
542 assert_eq!(decoded.msg_max_size, 1472);
543 assert_eq!(decoded.msg_flags.security_level, SecurityLevel::AuthNoPriv);
544 assert!(decoded.msg_flags.reportable);
545 assert_eq!(decoded.msg_security_model, SecurityModel::Usm);
546 }
547
548 #[test]
549 fn test_scoped_pdu_roundtrip() {
550 let pdu = Pdu::get_request(42, &[oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)]);
551 let scoped = ScopedPdu::new(b"engine".as_slice(), b"ctx".as_slice(), pdu);
552
553 let mut buf = EncodeBuf::new();
554 scoped.encode(&mut buf);
555 let encoded = buf.finish();
556
557 let mut decoder = Decoder::new(encoded);
558 let decoded = ScopedPdu::decode(&mut decoder).unwrap();
559
560 assert_eq!(decoded.context_engine_id.as_ref(), b"engine");
561 assert_eq!(decoded.context_name.as_ref(), b"ctx");
562 assert_eq!(decoded.pdu.request_id, 42);
563 }
564
565 #[test]
566 fn test_v3_message_plaintext_roundtrip() {
567 let global =
568 MsgGlobalData::new(100, 1472, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true));
569 let pdu = Pdu::get_request(42, &[oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)]);
570 let scoped = ScopedPdu::with_empty_context(pdu);
571 let msg = V3Message::new(global, Bytes::from_static(b"usm-params"), scoped);
572
573 let encoded = msg.encode();
574 let decoded = V3Message::decode(encoded).unwrap();
575
576 assert_eq!(decoded.global_data.msg_id, 100);
577 assert_eq!(decoded.security_level(), SecurityLevel::NoAuthNoPriv);
578 assert_eq!(decoded.security_params.as_ref(), b"usm-params");
579
580 let scoped_pdu = decoded.scoped_pdu().unwrap();
581 assert_eq!(scoped_pdu.pdu.request_id, 42);
582 }
583
584 #[test]
585 fn test_v3_message_encrypted_roundtrip() {
586 let global = MsgGlobalData::new(200, 1472, MsgFlags::new(SecurityLevel::AuthPriv, false));
587 let msg = V3Message::new_encrypted(
588 global,
589 Bytes::from_static(b"usm-params"),
590 Bytes::from_static(b"encrypted-data"),
591 );
592
593 let encoded = msg.encode();
594 let decoded = V3Message::decode(encoded).unwrap();
595
596 assert_eq!(decoded.global_data.msg_id, 200);
597 assert_eq!(decoded.security_level(), SecurityLevel::AuthPriv);
598
599 match &decoded.data {
600 V3MessageData::Encrypted(data) => {
601 assert_eq!(data.as_ref(), b"encrypted-data");
602 }
603 V3MessageData::Plaintext(_) => panic!("expected encrypted data"),
604 }
605 }
606
607 #[test]
608 fn test_msg_global_data_rejects_msg_max_size_below_minimum() {
609 let global = MsgGlobalData {
611 msg_id: 100,
612 msg_max_size: 400, msg_flags: MsgFlags::new(SecurityLevel::NoAuthNoPriv, true),
614 msg_security_model: SecurityModel::Usm,
615 };
616
617 let mut buf = EncodeBuf::new();
618 global.encode(&mut buf);
619 let encoded = buf.finish();
620
621 let mut decoder = Decoder::new(encoded);
622 let result = MsgGlobalData::decode(&mut decoder);
623
624 assert!(result.is_err());
625 match result.unwrap_err() {
626 Error::Decode {
627 kind: DecodeErrorKind::MsgMaxSizeTooSmall { value, minimum },
628 ..
629 } => {
630 assert_eq!(value, 400);
631 assert_eq!(minimum, 484);
632 }
633 e => panic!("expected MsgMaxSizeTooSmall error, got {:?}", e),
634 }
635 }
636
637 #[test]
638 fn test_msg_global_data_accepts_msg_max_size_at_minimum() {
639 let global = MsgGlobalData::new(100, 484, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true));
641
642 let mut buf = EncodeBuf::new();
643 global.encode(&mut buf);
644 let encoded = buf.finish();
645
646 let mut decoder = Decoder::new(encoded);
647 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
648
649 assert_eq!(decoded.msg_max_size, 484);
650 }
651
652 #[test]
653 fn test_msg_global_data_rejects_unknown_security_model() {
654 let mut buf = EncodeBuf::new();
657 buf.push_sequence(|buf| {
658 buf.push_integer(99); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(100); });
663 let encoded = buf.finish();
664
665 let mut decoder = Decoder::new(encoded);
666 let result = MsgGlobalData::decode(&mut decoder);
667
668 assert!(result.is_err());
669 match result.unwrap_err() {
670 Error::Decode {
671 kind: DecodeErrorKind::UnknownSecurityModel(model),
672 ..
673 } => {
674 assert_eq!(model, 99);
675 }
676 e => panic!("expected UnknownSecurityModel error, got {:?}", e),
677 }
678 }
679
680 #[test]
681 fn test_msg_global_data_accepts_usm_security_model() {
682 let global =
684 MsgGlobalData::new(100, 1472, MsgFlags::new(SecurityLevel::NoAuthNoPriv, true));
685
686 let mut buf = EncodeBuf::new();
687 global.encode(&mut buf);
688 let encoded = buf.finish();
689
690 let mut decoder = Decoder::new(encoded);
691 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
692
693 assert_eq!(decoded.msg_security_model, SecurityModel::Usm);
694 }
695
696 #[test]
705 fn test_msg_global_data_rejects_negative_msg_id() {
706 let mut buf = EncodeBuf::new();
709 buf.push_sequence(|buf| {
710 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(-1); });
715 let encoded = buf.finish();
716
717 let mut decoder = Decoder::new(encoded);
718 let result = MsgGlobalData::decode(&mut decoder);
719
720 assert!(result.is_err());
721 match result.unwrap_err() {
722 Error::Decode {
723 kind: DecodeErrorKind::InvalidMsgId { value },
724 ..
725 } => {
726 assert_eq!(value, -1);
727 }
728 e => panic!("expected InvalidMsgId error, got {:?}", e),
729 }
730 }
731
732 #[test]
733 fn test_msg_global_data_rejects_negative_msg_max_size() {
734 let mut buf = EncodeBuf::new();
737 buf.push_sequence(|buf| {
738 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(-1); buf.push_integer(100); });
743 let encoded = buf.finish();
744
745 let mut decoder = Decoder::new(encoded);
746 let result = MsgGlobalData::decode(&mut decoder);
747
748 assert!(result.is_err());
749 match result.unwrap_err() {
750 Error::Decode {
751 kind: DecodeErrorKind::MsgMaxSizeTooLarge { value },
752 ..
753 } => {
754 assert_eq!(value, -1);
755 }
756 e => panic!("expected MsgMaxSizeTooLarge error, got {:?}", e),
757 }
758 }
759
760 #[test]
761 fn test_msg_global_data_accepts_msg_id_at_zero() {
762 let mut buf = EncodeBuf::new();
764 buf.push_sequence(|buf| {
765 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(0); });
770 let encoded = buf.finish();
771
772 let mut decoder = Decoder::new(encoded);
773 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
774
775 assert_eq!(decoded.msg_id, 0);
776 }
777
778 #[test]
779 fn test_msg_global_data_accepts_msg_id_at_maximum() {
780 let mut buf = EncodeBuf::new();
782 buf.push_sequence(|buf| {
783 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(1472); buf.push_integer(i32::MAX); });
788 let encoded = buf.finish();
789
790 let mut decoder = Decoder::new(encoded);
791 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
792
793 assert_eq!(decoded.msg_id, i32::MAX);
794 }
795
796 #[test]
797 fn test_msg_global_data_accepts_msg_max_size_at_maximum() {
798 let mut buf = EncodeBuf::new();
800 buf.push_sequence(|buf| {
801 buf.push_integer(3); buf.push_octet_string(&[0x04]); buf.push_integer(i32::MAX); buf.push_integer(100); });
806 let encoded = buf.finish();
807
808 let mut decoder = Decoder::new(encoded);
809 let decoded = MsgGlobalData::decode(&mut decoder).unwrap();
810
811 assert_eq!(decoded.msg_max_size, i32::MAX);
812 }
813}