/// <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>
        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
            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);

            return(_userSecurityModel);
        }
Exemplo n.º 2
0
        /// <summary>Decode BER encoded SNMP version 1 trap packet</summary>
        /// <param name="buffer">BER encoded buffer</param>
        /// <param name="offset">Offset in the packet to start decoding from</param>
        /// <returns>Buffer position after the decoded value.</returns>
        /// <exception cref="SnmpException">Invalid SNMP Pdu type received. Not an SNMP version 1 Trap PDU.</exception>
        /// <exception cref="SnmpException">Invalid Variable Binding list encoding.</exception>
        public override int decode(byte[] buffer, int offset)
        {
            int  headerLength;
            byte asnType = ParseHeader(buffer, ref offset, out headerLength);

            if (asnType != (byte)PduType.Trap)
            {
                throw new SnmpException("Invalid PDU type.");
            }

            if (headerLength > buffer.Length - offset)
            {
                throw new OverflowException("Packet is too short.");
            }

            offset = _enterprise.decode(buffer, offset);
            offset = _agentAddr.decode(buffer, offset);

            offset = _generic.decode(buffer, offset);

            offset = _specific.decode(buffer, offset);

            offset = _timeStamp.decode(buffer, offset);

            // clean out the current variables
            _variables.Clear();

            offset = _variables.decode(buffer, offset);

            return(offset);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Decode USM portion of the SNMP version 3 packet.
        /// </summary>
        /// <param name="buffer">Received SNMP packet BER encoded</param>
        /// <param name="offset">Offset within the buffer to start decoding USM information</param>
        /// <returns>Buffer position after the decoded value</returns>
        /// <exception cref="SnmpDecodingException">Thrown when decoding enountered invalid data type in USM information</exception>
        /// <exception cref="OverflowException">Thrown when packet is too small to contain information length specified in header</exception>
        public override int decode(byte[] buffer, int offset)
        {
            // Grab the octet string header
            int  len;
            byte type = ParseHeader(buffer, ref offset, out len);

            if (type != OCTETSTRING)
            {
                throw new SnmpDecodingException("Invalid value type found while looking for USM header.");
            }

            if (len > (buffer.Length - offset))
            {
                throw new OverflowException("Packet too small");
            }
            // Now grab the sequence header
            type = ParseHeader(buffer, ref offset, out len);
            if (type != SnmpConstants.SMI_SEQUENCE)
            {
                throw new SnmpDecodingException("Sequence missing from USM header.");
            }

            if (len > (buffer.Length - offset))
            {
                throw new OverflowException("Packet too small");
            }

            // now grab values one at the time
            offset = _engineId.decode(buffer, offset);

            offset = _engineBoots.decode(buffer, offset);

            offset = _engineTime.decode(buffer, offset);

            offset = _securityName.decode(buffer, offset);

            int saveOffset = offset;

            offset = _authenticationParameters.decode(buffer, offset);

            if (_authenticationParameters.Length > 0)
            {
                // walk through and set the authentication parameters to 0x00 in the packet

                saveOffset += 2;                 // Skip BER encoded variable type and length
                for (int i = 0; i < _authenticationParameters.Length; i++)
                {
                    buffer[saveOffset + i] = 0x00;
                }
            }
            offset = _privacyParameters.decode(buffer, offset);
            return(offset);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Decode BER encoded Pdu
        /// </summary>
        /// <remarks>
        /// Decodes the protocol data unit from the passed buffer. If an error
        /// occurs during the decoding sequence then an AsnDecodingException is
        /// thrown by the method. The value is decoded using the AsnEncoder
        /// passed to the object.
        /// </remarks>
        /// <param name="buffer">BER encoded buffer</param>
        /// <param name="offset">The offset byte to begin decoding</param>
        /// <returns>Buffer position after the decoded value</returns>
        /// <exception cref="OverflowException">Thrown when header points to more data then is available.</exception>
        public override int decode(byte[] buffer, int offset)
        {
            int  headerLength;
            byte asnType = ParseHeader(buffer, ref offset, out headerLength);

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

            _asnType = asnType;

            // request id
            offset = _requestId.decode(buffer, offset);

            // error status
            offset = _errorStatus.decode(buffer, offset);

            // error index
            offset = _errorIndex.decode(buffer, offset);

            // clean out the current variables
            _vbs.Clear();

            // decode the Variable binding collection
            offset = _vbs.decode(buffer, offset);

            // if Pdu is an SNMP version 2 TRAP, remove sysUpTime and trapObjectID from the VarBinds array
            if (Type == PduType.V2Trap || Type == PduType.Inform)
            {
                if (_vbs.Count > 0)
                {
                    if (_vbs[0].Oid.Equals(SnmpConstants.SysUpTime))
                    {
                        _trapTimeStamp.Set(_vbs[0].Value);
                        _vbs.RemoveAt(0);                         // remove sysUpTime
                    }
                }
                if (_vbs.Count > 0)
                {
                    if (_vbs[0].Oid.Equals(SnmpConstants.TrapObjectId))
                    {
                        _trapObjectID.Set((Oid)_vbs[0].Value);
                        _vbs.RemoveAt(0);                         // remove sysUpTime
                    }
                }
            }

            return(offset);
        }
Exemplo n.º 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>
        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);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Decode SNMP packet header. This class decodes the initial sequence and SNMP protocol version
        /// number.
        /// </summary>
        /// <param name="buffer">BER encoded SNMP packet</param>
        /// <param name="length">Packet length</param>
        /// <returns>Offset position after the initial sequence header and protocol version value</returns>
        public virtual int decode(byte[] buffer, int length)
        {
            int offset = 0;

            if (length < 2)
            {
                // we need at least 2 bytes
                throw new OverflowException("Packet too small.");
            }
            // make sure you get the right length buffer to be able to check for over/under flow errors
            MutableByte buf = new MutableByte(buffer, length);
            Sequence    seq = new Sequence();

            offset = seq.decode(buf, offset);
            offset = _protocolVersion.decode(buf, offset);
            return(offset);
        }
Exemplo n.º 7
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);
        }
Exemplo n.º 8
0
        /// <summary>
        ///     Decode SNMP packet header. This class decodes the initial sequence and SNMP protocol version
        ///     number.
        /// </summary>
        /// <param name="buffer">BER encoded SNMP packet</param>
        /// <param name="length">Packet length</param>
        /// <returns>Offset position after the initial sequence header and protocol version value</returns>
        /// <exception cref="SnmpDecodingException">
        ///     Thrown when invalid sequence type is found at the start of the SNMP packet
        ///     being decoded
        /// </exception>
        public virtual int decode(byte[] buffer, int length)
        {
            var offset = 0;

            if (length < 2)
            {
                throw new OverflowException("Packet too small.");
            }
            // make sure you get the right length buffer to be able to check for over/under flow errors
            var buf = new MutableByte(buffer, length);
            var seq = new Sequence();

            offset = seq.decode(buf, offset);
            if (seq.Type != SnmpConstants.SMI_SEQUENCE)
            {
                throw new SnmpDecodingException("Invalid sequence type at the start of the SNMP packet.");
            }
            offset = _protocolVersion.decode(buf, offset);
            return(offset);
        }
Exemplo n.º 9
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>
        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)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 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 = _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(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 (_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.");

                // Initialize a temporary OctetString class to hold encrypted ScopedPdu
                OctetString encryptedScopedPdu = new OctetString();
                _ = 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;
        }