ParseHeader() static private method

Parse ASN.1 header.
Thrown when buffer is too short Thrown when invalid type is encountered in the header
static private ParseHeader ( byte mb, int &offset, int &length ) : byte
mb byte BER encoded data
offset int Offset in the packet to start parsing the header from
length int Length of the data in the section starting with parsed header
return byte
Example #1
0
        /// <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);
        }
Example #2
0
        /// <summary>
        /// Decode received SNMP packet.
        /// </summary>
        /// <param name="buffer">BER encoded packet buffer</param>
        /// <param name="length">BER encoded packet buffer length</param>
        /// <exception cref="SnmpException">Thrown when invalid encoding has been found in the packet</exception>
        /// <exception cref="OverflowException">Thrown when parsed header points to more data then is available in the packet</exception>
        /// <exception cref="SnmpInvalidVersionException">Thrown when parsed packet is not SNMP version 1</exception>
        /// <exception cref="SnmpInvalidPduTypeException">Thrown when received PDU is of a type not supported by SNMP version 1</exception>
        public override int Decode(byte[] buffer, int length)
        {
            MutableByte buf = new MutableByte(buffer, length);

            int offset = 0;

            offset = base.Decode(buffer, buffer.Length);

            if (Version != SnmpVersion.Ver2)
            {
                throw new SnmpInvalidVersionException("Invalid protocol version");
            }

            offset = _snmpCommunity.Decode(buf, offset);
            int  tmpOffset = offset;
            byte asnType   = AsnType.ParseHeader(buf, ref tmpOffset, out int headerLength);

            // Check packet length
            if (headerLength + offset > buf.Length)
            {
                throw new OverflowException("Insufficient data in packet");
            }

            if (asnType != (byte)PduType.Get && asnType != (byte)PduType.GetNext && asnType != (byte)PduType.Set &&
                asnType != (byte)PduType.GetBulk && asnType != (byte)PduType.Response && asnType != (byte)PduType.V2Trap &&
                asnType != (byte)PduType.Inform)
            {
                throw new SnmpInvalidPduTypeException("Invalid SNMP operation received: " + string.Format("0x{0:x2}", asnType));
            }

            // Now process the Protocol Data Unit
            offset = Pdu.Decode(buf, offset);
            return(length);
        }
Example #3
0
        /// <summary>
        /// Get SNMP protocol version from the packet. This routine does not verify if version number is valid. Caller
        /// should verify that returned value represents a valid SNMP protocol version number.
        ///
        /// <code>
        /// int protocolVersion = Packet.GetProtocolVersion(inPacket, inLength);
        /// if( protocolVersion != -1 )
        /// {
        ///     if( protocolVersion == SnmpConstants.SNMPV1 || protocolVersion == SnmpConstants.SNMPV2 || protocolVersion == SnmpConstants.SNMPV3 )
        ///     {
        ///         // do something
        ///     }
        ///     else
        ///     {
        ///         Console.WriteLine("Invalid SNMP protocol version.");
        ///     }
        /// }
        /// else
        /// {
        ///     Console.WriteLine("Invalid SNMP packet.");
        /// }
        /// </code>
        /// </summary>
        /// <param name="buffer">BER encoded SNMP packet</param>
        /// <param name="bufferLength">Length of the BER encoded packet</param>
        /// <returns>Returns SNMP protocol version, if packet is not valid returned value is -1.</returns>
        public static int GetProtocolVersion(byte[] buffer, int bufferLength)
        {
            int  offset  = 0;
            int  length  = 0;
            byte asnType = AsnType.ParseHeader(buffer, ref offset, out length);

            if ((offset + length) > bufferLength)
            {
                return(-1);                // This is not a valid packet
            }
            Integer32 version = new Integer32();

            offset = version.decode(buffer, offset);
            return(version.Value);
        }
Example #4
0
        /// <summary>
        /// Get SNMP protocol version from the packet. This routine does not verify if version number is valid. Caller
        /// should verify that returned value represents a valid SNMP protocol version number.
        ///
        /// <code>
        /// int protocolVersion = Packet.GetProtocolVersion(inPacket, inLength);
        /// if( protocolVersion != -1 )
        /// {
        ///     if( protocolVersion == SnmpConstants.SNMPV1 || protocolVersion == SnmpConstants.SNMPV2 || protocolVersion == SnmpConstants.SNMPV3 )
        ///     {
        ///         // do something
        ///     }
        ///     else
        ///     {
        ///         Console.WriteLine("Invalid SNMP protocol version.");
        ///     }
        /// }
        /// else
        /// {
        ///     Console.WriteLine("Invalid SNMP packet.");
        /// }
        /// </code>
        /// </summary>
        /// <param name="buffer">BER encoded SNMP packet</param>
        /// <param name="bufferLength">Length of the BER encoded packet</param>
        /// <returns>Returns SNMP protocol version, if packet is not valid returned value is -1.</returns>
        /// <exception cref="SnmpDecodingException">Thrown when invalid sequence type is found at the start of the SNMP packet being decoded</exception>
        public static int GetProtocolVersion(byte[] buffer, int bufferLength)
        {
            int  offset  = 0;
            byte asnType = AsnType.ParseHeader(buffer, ref offset, out int length);

            if ((offset + length) > bufferLength)
            {
                return(-1); // This is not a valid packet
            }
            if (asnType != SnmpConstants.SMI_SEQUENCE)
            {
                throw new SnmpDecodingException("Invalid sequence type at the start of the SNMP packet.");
            }
            Integer32 version = new Integer32();

            _ = version.decode(buffer, offset);
            return(version.Value);
        }
Example #5
0
        /// <summary>
        /// Get SNMP protocol version from the packet. This routine does not verify if version number is valid. Caller
        /// should verify that returned value represents a valid SNMP protocol version number.
        ///
        /// <code>
        /// int protocolVersion = Packet.GetProtocolVersion(inPacket, inLength);
        /// if( protocolVersion != -1 )
        /// {
        ///     if( protocolVersion == SnmpConstants.SNMPV1 || protocolVersion == SnmpConstants.SNMPV2 || protocolVersion == SnmpConstants.SNMPV3 )
        ///         // do something
        ///     else
        ///         Console.WriteLine("Invalid SNMP protocol version.");
        /// }
        /// else
        ///     Console.WriteLine("Invalid SNMP packet.");
        /// </code>
        /// </summary>
        /// <param name="buffer">BER encoded SNMP packet</param>
        /// <param name="bufferLength">Length of the BER encoded packet</param>
        /// <returns>Returns SNMP protocol version, if packet is not valid returned value is -1.</returns>
        /// <exception cref="SnmpDecodingException">Thrown when invalid sequence type is found at the start of the SNMP packet being decoded</exception>
        public static ESnmpVersion GetProtocolVersion(byte[] buffer, int bufferLength)
        {
            int offset = 0;

            byte asnType = AsnType.ParseHeader(buffer, ref offset, out int length);

            if ((offset + length) > bufferLength)
            {
                throw new SnmpDecodingException("Cannot parse SNMP version from packet, input past end");
            }

            if (asnType != SnmpConstants.SmiSequence)
            {
                throw new SnmpDecodingException("Invalid sequence type at the start of the SNMP packet.");
            }

            Integer32 version = new Integer32();

            offset = version.Decode(buffer, offset);

            return((ESnmpVersion)version.Value);
        }
        /// <summary>
        /// Decode received packet. This method overrides the base implementation that cannot be used with this type of the packet.
        /// </summary>
        /// <param name="buffer">Packet buffer</param>
        /// <param name="length">Buffer length</param>
        public override int decode(byte[] buffer, int length)
        {
            int         offset = 0;
            MutableByte buf    = new MutableByte(buffer, length);

            offset = base.decode(buffer, length);


            // parse community
            offset = _snmpCommunity.decode(buf, offset);

            // look ahead to make sure this is a TRAP packet
            int  tmpOffset  = offset;
            byte tmpAsnType = AsnType.ParseHeader(buffer, ref tmpOffset, out _);

            if (tmpAsnType != (byte)PduType.Trap)
            {
                throw new SnmpException(string.Format("Invalid SNMP ASN.1 type. Received: {0:x2}", tmpAsnType));
            }
            // decode protocol data unit
            offset = this.Pdu.decode(buf, offset);
            return(offset);
        }
Example #7
0
        /// <summary>
        /// Decode SNMP version 3 packet. This method will perform authentication check and decode privacy protected <see cref="ScopedPdu"/>. This method will
        /// not check for the timeliness of the packet, correct engine boot value or engine id because it does not have a reference to the engine time prior to this call.
        /// </summary>
        /// <param name="berBuffer">BER encoded SNMP version 3 packet buffer</param>
        /// <param name="length">Buffer length</param>
        /// <param name="authKey">Authentication key (not password)</param>
        /// <param name="privKey">Privacy key (not password)</param>
        /// <returns>The length of the decoded segment</returns>
        public int Decode(byte[] berBuffer, int length, byte[] authKey, byte[] privKey)
        {
            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)ESnmpVersion.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.SmiSequence)
            {
                throw new SnmpDecodingException("Invalid sequence type in 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 = messageFlags.Decode(buffer, offset);

            // verify that a valid authentication/privacy configuration is present in the packet
            if (messageFlags.Authentication == false && messageFlags.Privacy == true)
            {
                throw new SnmpException(SnmpException.EErrorCode.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 != userSecurityModel.Type)
            {
                throw new SnmpException(SnmpException.EErrorCode.UnsupportedSecurityModel, "Class only support SNMP Version 3 User Security Model.");
            }

            // parse user security model
            offset = userSecurityModel.Decode(buffer, offset);

            // Authenticate message if authentication flag is set and packet is not a discovery packet
            if (messageFlags.Authentication && userSecurityModel.EngineId.Length > 0)
            {
                // Authenticate packet
                if (userSecurityModel.AuthenticationParameters.Length != 12)
                {
                    throw new SnmpAuthenticationException("Invalid authentication parameter field length.");
                }
                if (!userSecurityModel.IsAuthentic(authKey, buffer))
                {
                    throw new SnmpAuthenticationException("Authentication of the incoming packet failed.");
                }
            }

            // Decode ScopedPdu if it is privacy protected and packet is not a discovery packet
            if (messageFlags.Privacy && userSecurityModel.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(userSecurityModel.Privacy);

                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.EErrorCode.UnsupportedPrivacyProtocol, "Privacy protocol requested is not supported.");
                }

                if (userSecurityModel.PrivacyParameters.Length != privacyProtocol.PrivacyParametersLength)
                {
                    throw new SnmpException(SnmpException.EErrorCode.InvalidPrivacyParameterLength, "Invalid privacy parameters field length.");
                }

                // Initialize a temporary OctetString class to hold encrypted ScopedPdu
                OctetString encryptedScopedPdu = new OctetString();
                offset = encryptedScopedPdu.Decode(buffer, offset);

                // decode encrypted packet
                byte[] decryptedScopedPdu = privacyProtocol.Decrypt(encryptedScopedPdu, 0, encryptedScopedPdu.Length, privKey, userSecurityModel.EngineBoots, userSecurityModel.EngineTime, userSecurityModel.PrivacyParameters);
                int    tempOffset         = 0;
                offset = scopedPdu.Decode(decryptedScopedPdu, tempOffset);
            }
            else
            {
                offset = scopedPdu.Decode(buffer, offset);
            }

            return(offset);
        }
        /// <summary>
        /// Decode SNMP version 3 packet. This method will perform authentication check and decode privacy protected <see cref="ScopedPdu"/>. This method will
        /// not check for the timeliness of the packet, correct engine boot value or engine id because it does not have a reference to the engine time prior to this call.
        /// </summary>
        /// <param name="berBuffer">BER encoded SNMP version 3 packet buffer</param>
        /// <param name="length">Buffer length</param>
        public override int decode(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
            int  len     = 0;
            byte asnType = AsnType.ParseHeader(buffer, ref offset, out len);

            // 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 != _userSecurityModel.Type)
            {
                throw new SnmpException(SnmpException.UnsupportedSecurityModel, "Class only support SNMP Version 3 User Security Model.");
            }

            // parse user security model
            offset = _userSecurityModel.decode(buffer, offset);

            // Authenticate message if authentication flag is set and packet is not a discovery packet
            if (_msgFlags.Authentication && _userSecurityModel.EngineId.Length > 0)
            {
                // Authenticate packet
                if (_userSecurityModel.AuthenticationParameters.Length != 12)
                {
                    throw new SnmpAuthenticationException("Invalid authentication parameter field length.");
                }
                if (!_userSecurityModel.IsAuthentic(buffer))
                {
                    throw new SnmpAuthenticationException("Authentication of the incoming packet failed.");
                }
            }

            // Decode ScopedPdu if it is privacy protected and packet is not a discovery packet
            if (_msgFlags.Privacy && _userSecurityModel.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(_userSecurityModel.Privacy);
                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedPrivacyProtocol, "Privacy protocol requested is not supported.");
                }
                if (_userSecurityModel.PrivacyParameters.Length != privacyProtocol.PrivacyParametersLength)
                {
                    throw new SnmpException(SnmpException.InvalidPrivacyParameterLength, "Invalid privacy parameters field length.");
                }

                // build privacy key
                IAuthenticationDigest auth = Authentication.GetInstance(_userSecurityModel.Authentication);
                if (auth == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedNoAuthPriv, "Invalid authentication protocol.");
                }

                byte[] pkey = auth.PasswordToKey(_userSecurityModel.PrivacySecret, _userSecurityModel.EngineId);

                // extend key if it is too short
                if (pkey.Length < privacyProtocol.MinimumKeyLength)
                {
                    pkey = privacyProtocol.ExtendShortKey(pkey, new OctetString(_userSecurityModel.PrivacySecret), _userSecurityModel.EngineId, auth);
                }

                // Initialize a temporary OctetString class to hold encrypted ScopedPdu
                OctetString encryptedScopedPdu = new OctetString();
                offset = encryptedScopedPdu.decode(buffer, offset);

                // decode encrypted packet
                byte[] decryptedScopedPdu = privacyProtocol.Decrypt(encryptedScopedPdu, 0, encryptedScopedPdu.Length, pkey, _userSecurityModel.EngineBoots, _userSecurityModel.EngineTime, _userSecurityModel.PrivacyParameters);
                int    tempOffset         = 0;
                offset = _scopedPdu.decode(decryptedScopedPdu, tempOffset);
            }
            else
            {
                offset = _scopedPdu.decode(buffer, offset);
            }
            return(offset);
        }