1 //! SNMPv3 Parser
2 //!
3 //! SNMPv3 is defined in the following RFCs:
4 //! - [RFC2570](https://tools.ietf.org/html/rfc2570): Introduction to SNMP v3
5 //! - [RFC3412](https://tools.ietf.org/html/rfc3412): Message Processing and Dispatching for the
6 //! Simple Network Management Protocol (SNMP)
7 //!
8 //! See also:
9 //! - [RFC2578](https://tools.ietf.org/html/rfc2578): Structure of Management Information Version 2 (SMIv2)
10
11 use std::fmt;
12
13 use der_parser::ber::*;
14 use der_parser::error::*;
15 use nom::IResult;
16
17 use crate::snmp::{SnmpPdu, parse_ber_octetstring_as_slice, parse_snmp_v2c_pdu};
18 pub use crate::usm::{UsmSecurityParameters,parse_usm_security_parameters};
19 use crate::error::SnmpError;
20
21 #[derive(Clone, Copy, Eq, PartialEq)]
22 pub struct SecurityModel(pub u32);
23
24 #[allow(non_upper_case_globals)]
25 impl SecurityModel {
26 pub const SnmpV1 : SecurityModel = SecurityModel(1);
27 pub const SnmpV2c : SecurityModel = SecurityModel(2);
28 pub const USM : SecurityModel = SecurityModel(3);
29 }
30
31 impl fmt::Debug for SecurityModel {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 match self.0 {
34 1 => f.write_str("SnmpV1"),
35 2 => f.write_str("SnmpV2c"),
36 3 => f.write_str("USM"),
37 n => f.debug_tuple("SecurityModel").field(&n).finish(),
38 }
39 }
40 }
41
42 #[derive(Debug,PartialEq)]
43 pub enum SecurityParameters<'a> {
44 Raw(&'a[u8]),
45 USM(UsmSecurityParameters<'a>)
46 }
47
48 /// An SNMPv3 message
49 #[derive(Debug,PartialEq)]
50 pub struct SnmpV3Message<'a> {
51 /// Version, as raw-encoded: 3 for SNMPv3
52 pub version: u32,
53 pub header_data: HeaderData,
54 pub security_params: SecurityParameters<'a>,
55 pub data: ScopedPduData<'a>,
56 }
57
58 #[derive(Clone, Copy, Debug, PartialEq)]
59 pub struct HeaderData {
60 pub msg_id: u32,
61 pub msg_max_size: u32,
62 pub msg_flags: u8,
63 pub msg_security_model: SecurityModel,
64 }
65
66 impl HeaderData {
is_authenticated(&self) -> bool67 pub fn is_authenticated(&self) -> bool { self.msg_flags & 0b001 != 0 }
68
is_encrypted(&self) -> bool69 pub fn is_encrypted(&self) -> bool { self.msg_flags & 0b010 != 0 }
70
is_reportable(&self) -> bool71 pub fn is_reportable(&self) -> bool { self.msg_flags & 0b100 != 0 }
72 }
73
74 #[derive(Debug,PartialEq)]
75 pub enum ScopedPduData<'a> {
76 Plaintext(ScopedPdu<'a>),
77 Encrypted(&'a[u8]),
78 }
79
80 #[derive(Debug,PartialEq)]
81 pub struct ScopedPdu<'a> {
82 pub ctx_engine_id: &'a[u8],
83 pub ctx_engine_name: &'a[u8],
84 /// ANY -- e.g., PDUs as defined in [RFC3416](https://tools.ietf.org/html/rfc3416)
85 pub data: SnmpPdu<'a>,
86 }
87
88
89
90
parse_snmp_v3_data<'a>(i:&'a[u8], hdr: &HeaderData) -> IResult<&'a[u8], ScopedPduData<'a>, BerError>91 pub(crate) fn parse_snmp_v3_data<'a>(i:&'a[u8], hdr: &HeaderData) -> IResult<&'a[u8], ScopedPduData<'a>, BerError> {
92 if hdr.is_encrypted()
93 {
94 map_res!(i,
95 parse_ber_octetstring,
96 |x: BerObject<'a>| x.as_slice().map(|x| ScopedPduData::Encrypted(x))
97 )
98 } else {
99 parse_snmp_v3_plaintext_pdu(i)
100 }
101 }
102
parse_secp<'a>(x:&BerObject<'a>, hdr:&HeaderData) -> Result<SecurityParameters<'a>, BerError>103 pub(crate) fn parse_secp<'a>(x:&BerObject<'a>, hdr:&HeaderData) -> Result<SecurityParameters<'a>, BerError> {
104 match x.as_slice() {
105 Ok(i) => {
106 match hdr.msg_security_model {
107 SecurityModel::USM => {
108 match parse_usm_security_parameters(i) {
109 Ok((_,usm)) => Ok(SecurityParameters::USM(usm)),
110 _ => Err(BerError::BerValueError)
111 }
112 },
113 _ => Ok(SecurityParameters::Raw(i))
114 }
115 },
116 _ => Err(BerError::BerValueError)
117 }
118 }
119
120 /// Parse an SNMPv3 top-level message
121 ///
122 /// Example:
123 ///
124 /// ```rust
125 /// # extern crate nom;
126 /// # #[macro_use] extern crate snmp_parser;
127 /// use snmp_parser::{parse_snmp_v3,ScopedPduData,SecurityModel};
128 ///
129 /// static SNMPV3_REQ: &'static [u8] = include_bytes!("../assets/snmpv3_req.bin");
130 ///
131 /// # fn main() {
132 /// match parse_snmp_v3(&SNMPV3_REQ) {
133 /// Ok((_, ref r)) => {
134 /// assert!(r.version == 3);
135 /// assert!(r.header_data.msg_security_model == SecurityModel::USM);
136 /// match r.data {
137 /// ScopedPduData::Plaintext(ref _pdu) => { },
138 /// ScopedPduData::Encrypted(_) => (),
139 /// }
140 /// },
141 /// Err(e) => panic!(e),
142 /// }
143 /// # }
144 /// ```
parse_snmp_v3<'a>(i:&'a[u8]) -> IResult<&'a[u8], SnmpV3Message<'a>, SnmpError>145 pub fn parse_snmp_v3<'a>(i:&'a[u8]) -> IResult<&'a[u8], SnmpV3Message<'a>, SnmpError> {
146 upgrade_error! {
147 parse_der_struct!(
148 i,
149 TAG BerTag::Sequence,
150 vers: parse_ber_u32 >>
151 hdr: parse_snmp_v3_headerdata >>
152 secp: map_res!(parse_ber_octetstring, |x: BerObject<'a>| parse_secp(&x,&hdr)) >>
153 data: call!(parse_snmp_v3_data,&hdr) >>
154 ({
155 SnmpV3Message{
156 version: vers,
157 header_data: hdr,
158 security_params: secp,
159 data
160 }
161 })
162 )
163 .map(|(rem,x)| (rem,x.1))
164 }
165 }
166
parse_snmp_v3_headerdata(i:&[u8]) -> IResult<&[u8], HeaderData, BerError>167 pub(crate) fn parse_snmp_v3_headerdata(i:&[u8]) -> IResult<&[u8], HeaderData, BerError> {
168 parse_der_struct!(
169 i,
170 TAG BerTag::Sequence,
171 id: parse_ber_u32 >>
172 sz: parse_ber_u32 >>
173 fl: map_res!(parse_ber_octetstring, |x: BerObject| x.as_slice().and_then(|s|
174 if s.len() == 1 { Ok(s[0]) } else { Err(BerError::BerValueError) })) >>
175 sm: parse_ber_u32 >>
176 (
177 HeaderData{
178 msg_id: id,
179 msg_max_size: sz,
180 msg_flags: fl,
181 msg_security_model: SecurityModel(sm),
182 }
183 )
184 ).map(|(rem,x)| (rem,x.1))
185 }
186
parse_snmp_v3_plaintext_pdu(i:&[u8]) -> IResult<&[u8], ScopedPduData, BerError>187 fn parse_snmp_v3_plaintext_pdu(i:&[u8]) -> IResult<&[u8], ScopedPduData, BerError> {
188 parse_der_struct!(
189 i,
190 ctx_eng_id: parse_ber_octetstring_as_slice >>
191 ctx_name: parse_ber_octetstring_as_slice >>
192 data: parse_snmp_v2c_pdu >>
193 (
194 ScopedPduData::Plaintext(ScopedPdu{
195 ctx_engine_id: ctx_eng_id,
196 ctx_engine_name: ctx_name,
197 data
198 })
199 )
200 ).map(|(rem,x)| (rem,x.1))
201 }
202