From 85633698a89f0eb3b12f70d6e52a40a571eedf4c Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Tue, 6 Aug 2019 22:56:33 +0200 Subject: Move SNMP engine discovery code to security module This SNMP engine ID discovery procedure is spread across message processing and security modules. This is weird! Anyway, this change moves SNMP message rewriting, associated with starting out SNMP discovery sequence, to security module. The motivation is to let security module making the ultimate decision whether or not SNMP engine discovery is required. For example, if localized keys are committed directly to the DB, security module may just use them without engine discovery phase. --- pysnmp/hlapi/v3arch/auth.py | 8 ++++++- pysnmp/proto/mpmod/rfc3412.py | 29 +++------------------- pysnmp/proto/secmod/rfc3414/service.py | 44 ++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 32 deletions(-) (limited to 'pysnmp') diff --git a/pysnmp/hlapi/v3arch/auth.py b/pysnmp/hlapi/v3arch/auth.py index c4302d52..9392664f 100644 --- a/pysnmp/hlapi/v3arch/auth.py +++ b/pysnmp/hlapi/v3arch/auth.py @@ -294,7 +294,9 @@ class UsmUserData(object): securityEngineId: :py:class:`~pysnmp.proto.rfc1902.OctetString` The snmpEngineID of the authoritative SNMP engine to which a dateRequest message is to be sent. Will be automatically - discovered from peer if not given. + discovered from peer if not given, unless localized keys + are used. In the latter case *securityEngineId* must be + specified. See :RFC:`3414#section-2.5.1` for technical explanation. @@ -330,6 +332,10 @@ class UsmUserData(object): * :py:class:`~pysnmp.hlapi.usmKeyTypeLocalized` + If `~pysnmp.hlapi.usmKeyTypeLocalized` is used, peer SNMP engine ID + discovery mechanism can't be leveraged for key localization, so + *securityEngineId* must be given by local configuration. + privKeyType: :py:class:`int` Type of `privKey` material. See :RFC:`3414#section-2.6` for technical explanation. diff --git a/pysnmp/proto/mpmod/rfc3412.py b/pysnmp/proto/mpmod/rfc3412.py index 20852db6..2062bf0e 100644 --- a/pysnmp/proto/mpmod/rfc3412.py +++ b/pysnmp/proto/mpmod/rfc3412.py @@ -234,33 +234,10 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): else: if peerSnmpEngineData is None: - # Force engineID discovery (rfc3414, 4) - securityEngineId = securityName = self._emptyStr - securityLevel = 1 - - # Clear possible auth&priv flags - headerData.setComponentByPosition( - 2, self._msgFlags[msgFlags & 0xfc], verifyConstraints=False, - matchTags=False, matchConstraints=False) - - # XXX - scopedPDU = self._scopedPDU - scopedPDU.setComponentByPosition( - 0, self._emptyStr, verifyConstraints=False, matchTags=False, - matchConstraints=False) - scopedPDU.setComponentByPosition(1, contextName) - scopedPDU.setComponentByPosition(2) - - # Use dead-empty PDU for engine-discovery report - emptyPdu = pdu.clone() - pMod.apiPDU.setDefaults(emptyPdu) - - scopedPDU.getComponentByPosition(2).setComponentByType( - emptyPdu.tagSet, emptyPdu, verifyConstraints=False, - matchTags=False, matchConstraints=False) - debug.logger & debug.FLAG_MP and debug.logger( - 'prepareOutgoingMessage: force engineID discovery') + 'prepareOutgoingMessage: peer SNMP engine is not known') + + securityEngineId = None else: securityEngineId = peerSnmpEngineData['securityEngineId'] diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index 74bdaff9..9fdfe707 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -16,6 +16,7 @@ from pyasn1.type import namedtype from pyasn1.type import univ from pysnmp import debug +from pysnmp.proto import api from pysnmp.proto import errind from pysnmp.proto import error from pysnmp.proto import rfc1155 @@ -33,6 +34,9 @@ from pysnmp.proto.secmod.rfc3826.priv import aes from pysnmp.proto.secmod.rfc7860.auth import hmacsha2 from pysnmp.smi.error import NoSuchInstanceError +# API to rfc1905 protocol objects +pMod = api.PROTOCOL_MODULES[api.SNMP_VERSION_2C] + # USM security params @@ -304,6 +308,8 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): snmpEngineID = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax + msg = globalData + # 3.1.1 if securityStateReference is not None: # 3.1.1a @@ -361,7 +367,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): securityEngineID.prettyPrint(), securityName, securityStateReference)) - elif securityName: + elif securityEngineID: # 3.1.1b try: (usmUserName, usmUserSecurityName, usmUserAuthProtocol, @@ -447,7 +453,35 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): raise error.StatusInformation(errorIndication=errind.invalidMsg) else: - # empty username used for engineID discovery + # 4. (start SNMP engine ID discovery) + securityEngineID = securityName = null + securityLevel = 1 + + scopedPDU.setComponentByPosition( + 0, null, verifyConstraints=False, + matchTags=False, matchConstraints=False) + + headerData = msg.getComponentByPosition(1) + + # Clear possible auth&priv flags + headerData.setComponentByPosition( + 2, univ.OctetString(hexValue='00'), verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + emptyPdu = scopedPDU.getComponentByPosition(2).getComponent() + + # we edit the rest of the structures in-place because they + # are ours for as long as this stack lasts, however PDU + # is more persistent and should not be touched + + emptyPdu = emptyPdu.clone() + pMod.apiPDU.setDefaults(emptyPdu) + + scopedPDU.getComponentByPosition(2).setComponentByType( + emptyPdu.tagSet, emptyPdu, verifyConstraints=False, + matchTags=False, matchConstraints=False) + usmUserName = usmUserSecurityName = null usmUserAuthProtocol = noauth.NoAuth.SERVICE_ID usmUserPrivProtocol = nopriv.NoPriv.SERVICE_ID @@ -456,6 +490,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): debug.logger & debug.FLAG_SM and debug.logger( '__generateRequestOrResponseMsg: using blank USM info ' + 'for peer SNMP engine ID discovery ' 'usmUserName "%s" ' 'usmUserSecurityName "%s" ' 'usmUserAuthProtocol "%s" ' @@ -466,9 +501,8 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized, - securityEngineID.prettyPrint(), securityName)) - - msg = globalData + securityEngineID and securityEngineID.prettyPrint(), + securityName)) # 3.1.2 if securityLevel == 3: -- cgit v1.2.1