diff options
-rw-r--r-- | pysnmp/hlapi/v3arch/auth.py | 8 | ||||
-rw-r--r-- | pysnmp/proto/mpmod/rfc3412.py | 29 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/service.py | 44 |
3 files changed, 49 insertions, 32 deletions
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: |