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