/// <summary>
/// "Look-ahead" decode of SNMP packet header including USM information
/// </summary>
/// <remarks>
/// Decode first component of the SNMP version 3 packet allowing the caller to retrieve USM SecureName needed to retrieve
/// client security parameters that will allow authentication and privacy decryption to take place.
///
/// This method is used to support Agent like behavior or to handle unsolicited packets like TRAP and INFORMs. In all of
/// these cases, sender of packets will forward a packet without a request being sent by you. In turn, you will need
/// to parse enough of the packet to retrieve SecureName which you can use to retrieve security parameters associated with
/// that user and attempt to authorize and privacy decrypt the received packet.
///
/// Only use this method when your application is acting as an Agent or if you need to process TRAP and INFORM packets.
/// </remarks>
/// <param name="berBuffer">Raw SNMP version 3 packet</param>
/// <param name="length">SNMP version 3 packet length</param>
/// <returns>UserSecurityModel class parsed from the parameter SNMP version 3 packet</returns>
/// <exception cref="SnmpInvalidVersionException">Thrown when attempting to parse an SNMP packet that is not version 3</exception>
/// <exception cref="OverflowException">Thrown when header specifies packet length that is longer then the amount of data received.</exception>
/// <exception cref="SnmpDecodingException">Thrown when invalid sequence is enountered while decoding global message data sequence</exception>
/// <exception cref="SnmpException">Thrown with SnmpException.UnsupportedNoAuthPriv when packet is using privacy without authentication (not allowed)</exception>
/// <exception cref="SnmpException">Thrown with SnmpException.UnsupportedSecurityModel when packet is sent with security model other then USM (only USM is defined in SNMPv3 standard)</exception>
public UserSecurityModel GetUSM(byte[] berBuffer, int length)
{
MutableByte buffer = new MutableByte(berBuffer, length);
int offset = 0;
// let base class parse first sequence and SNMP version number
offset = base.Decode(buffer, length);
// check for correct SNMP protocol version
if (_protocolVersion != (int)SnmpVersion.Ver3)
{
throw new SnmpInvalidVersionException("Expecting SNMP version 3.");
}
// now grab the global message data sequence header information
byte asnType = AsnType.ParseHeader(buffer, ref offset, out int len);
if (asnType != SnmpConstants.SMI_SEQUENCE)
{
throw new SnmpDecodingException("Invalid sequence type when decoding global message data sequence.");
}
// check that packet size can accommodate the length specified in the header
if (len > (buffer.Length - offset))
{
throw new OverflowException("Packet is too small to contain the data described in the header.");
}
// retrieve message id
offset = _messageId.Decode(buffer, offset);
// max message size
offset = _maxMessageSize.Decode(buffer, offset);
// message flags
offset = MsgFlags.Decode(buffer, offset);
// verify that a valid authentication/privacy configuration is present in the packet
if (MsgFlags.Authentication == false && MsgFlags.Privacy == true)
{
throw new SnmpException(SnmpException.UnsupportedNoAuthPriv,
"SNMP version 3 noAuthPriv security combination is not supported.");
}
// security model code
offset = _securityModel.Decode(buffer, offset);
// we only support USM. code = 0x03
if (_securityModel.Value != USM.Type)
{
throw new SnmpException(SnmpException.UnsupportedSecurityModel,
"Class only support SNMP Version 3 User Security Model.");
}
// parse user security model
offset = USM.Decode(buffer, offset);
return(USM);
}