Message flags in the SNMP v3 header.
Message flags hold flags that indicate if packet is authenticated, privacy protected and if report reply is expected on errors. Message flags field is a 1 byte OctetString encoded field.
Inheritance: AsnType, ICloneable
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>
 /// Standard constructor.
 /// </summary>
 public SnmpV3Packet()
     : base(SnmpVersion.Ver3)
 {
     _messageId           = new Integer32();
     _maxMessageSize      = new Integer32(64 * 1024);
     _msgFlags            = new MsgFlags();
     _msgFlags.Reportable = true;             // Make sure reportable is set to true by default
     _securityModel       = new Integer32();
     _userSecurityModel   = new UserSecurityModel();
     _scopedPdu           = new ScopedPdu();
 }
Example #3
0
        /// <summary>Standard constructor.</summary>
        public SnmpV3Packet()
            : base(ESnmpVersion.Ver3)
        {
            messageId      = new Integer32();
            maxMessageSize = new Integer32(64 * 1024);

            messageFlags = new MsgFlags
            {
                Reportable = true, // Make sure reportable is set to true by default
            };

            securityModel     = new Integer32();
            userSecurityModel = new UserSecurityModel();
            scopedPdu         = new ScopedPdu();
        }
Example #4
0
 /// <summary>
 /// Standard constructor.
 /// </summary>
 public SnmpV3Packet()
     : base(SnmpVersion.Ver3)
 {
     _messageId = new Integer32();
     _maxMessageSize = new Integer32(64 * 1024);
     _msgFlags = new MsgFlags();
     _msgFlags.Reportable = true; // Make sure reportable is set to true by default
     _securityModel = new Integer32();
     _userSecurityModel = new UserSecurityModel();
     _scopedPdu = new ScopedPdu();
 }
Example #5
0
        /// <summary>
        /// Encode SNMP version 3 packet
        /// </summary>
        /// <param name="authKey">Authentication key (not password)</param>
        /// <param name="privKey">Privacy key (not password)</param>
        /// <remarks>
        /// Before encoding the packet into a byte array you need to ensure all required information is
        /// set. Examples of required information is request type, Vbs (Oid + values pairs), USM settings including
        /// SecretName, authentication method and secret (if needed), privacy method and secret (if needed), etc.
        /// </remarks>
        /// <returns>Byte array BER encoded SNMP packet.</returns>
        public byte[] Encode(byte[] authKey, byte[] privKey)
        {
            MutableByte buffer = new MutableByte();
            // encode the global message data sequence header information

            MutableByte globalMessageData = new MutableByte();

            // if message id is 0 then generate a new, random message id
            if (_messageId.Value == 0)
            {
                Random rand = new Random();
                _messageId.Value = rand.Next(1, Int32.MaxValue);
            }

            // encode message id
            _messageId.Encode(globalMessageData);

            // encode max message size
            _maxMessageSize.Encode(globalMessageData);

            // message flags
            MsgFlags.Encode(globalMessageData);

            // security model code
            _securityModel.Value = USM.Type;
            _securityModel.Encode(globalMessageData);

            // add global message data to the main buffer
            // encode sequence header and add data
            AsnType.BuildHeader(buffer, SnmpConstants.SMI_SEQUENCE, globalMessageData.Length);
            buffer.Append(globalMessageData);

            MutableByte packetHeader = new MutableByte(buffer);

            // before going down this road, check if this is a discovery packet
            OctetString savedUserName  = new OctetString();
            bool        privacy        = MsgFlags.Privacy;
            bool        authentication = MsgFlags.Authentication;
            bool        reportable     = MsgFlags.Reportable;

            if (USM.EngineId.Length <= 0)
            {
                // save USM settings prior to encoding a Discovery packet
                savedUserName.Set(USM.SecurityName);
                USM.SecurityName.Reset(); // delete security name for discovery packets
                MsgFlags.Authentication = false;
                MsgFlags.Privacy        = false;
                MsgFlags.Reportable     = true;
            }

            USM.Encode(buffer);

            if (USM.EngineId.Length <= 0)
            {
                // restore saved USM values
                USM.SecurityName.Set(savedUserName);
                MsgFlags.Authentication = authentication;
                MsgFlags.Privacy        = privacy;
                MsgFlags.Reportable     = reportable;
            }

            // Check if privacy encryption is required
            MutableByte encodedPdu = new MutableByte();

            if (MsgFlags.Privacy && USM.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(USM.Privacy);
                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedPrivacyProtocol, "Specified privacy protocol is not supported.");
                }

                // Get BER encoded ScopedPdu
                MutableByte unencryptedPdu = new MutableByte();
                ScopedPdu.Encode(unencryptedPdu);

                // we have to expand the key
                IAuthenticationDigest auth = Authentication.GetInstance(USM.Authentication);
                if (auth == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedNoAuthPriv, "Invalid authentication protocol. noAuthPriv mode not supported.");
                }

                byte[] encryptedBuffer = privacyProtocol.Encrypt(unencryptedPdu, 0, unencryptedPdu.Length, privKey, USM.EngineBoots, USM.EngineTime, out byte[] privacyParameters, auth);

                USM.PrivacyParameters.Set(privacyParameters);
                OctetString encryptedOctetString = new OctetString(encryptedBuffer);
                encryptedOctetString.Encode(encodedPdu);
                // now redo packet encoding
                buffer.Reset();
                buffer.Set(packetHeader);
                USM.Encode(buffer);
                int preEncodedLength = encodedPdu.Length;
                buffer.Append(encodedPdu);
                if (_maxMessageSize.Value != 0)
                {
                    // verify compliance with maximum message size
                    if ((encodedPdu.Length - preEncodedLength) > _maxMessageSize)
                    {
                        throw new SnmpException(SnmpException.MaximumMessageSizeExceeded, "ScopedPdu exceeds maximum message size.");
                    }
                }
            }
            else
            {
                ScopedPdu.Encode(encodedPdu);
                buffer.Append(encodedPdu);
            }

            base.Encode(buffer);

            if (MsgFlags.Authentication && USM.EngineId.Length > 0)
            {
                USM.Authenticate(authKey, ref buffer);
                // Now re-encode the packet with the authentication information
                USM.Encode(packetHeader);
                packetHeader.Append(encodedPdu);
                base.Encode(packetHeader);
                buffer = packetHeader;
            }
            return(buffer);
        }
Example #6
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 != 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);

            // Authenticate message if authentication flag is set and packet is not a discovery packet
            if (MsgFlags.Authentication && USM.EngineId.Length > 0)
            {
                // Authenticate packet
                if (USM.AuthenticationParameters.Length != 12)
                {
                    throw new SnmpAuthenticationException("Invalid authentication parameter field length.");
                }

                if (!USM.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 && USM.EngineId.Length > 0)
            {
                IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(USM.Privacy);
                if (privacyProtocol == null)
                {
                    throw new SnmpException(SnmpException.UnsupportedPrivacyProtocol, "Privacy protocol requested is not supported.");
                }
                if (USM.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();
                offset = encryptedScopedPdu.Decode(buffer, offset);

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

            return(offset);
        }