summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2019-08-06 22:56:33 +0200
committerIlya Etingof <etingof@gmail.com>2019-08-06 22:56:33 +0200
commitc351e90391b7772c3d93e63b64d479cae5f44f6b (patch)
tree523f5645b6f21d53024d645a58c5e944a441b05d
parent89d14d560a00f2ac1ab7228f00e0edbeedb31808 (diff)
downloadpysnmp-git-c351e90391b7772c3d93e63b64d479cae5f44f6b.tar.gz
Move most of 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.
-rw-r--r--pysnmp/hlapi/auth.py8
-rw-r--r--pysnmp/proto/mpmod/rfc3412.py25
-rw-r--r--pysnmp/proto/secmod/rfc3414/service.py46
3 files changed, 50 insertions, 29 deletions
diff --git a/pysnmp/hlapi/auth.py b/pysnmp/hlapi/auth.py
index 13120a6d..e784eec8 100644
--- a/pysnmp/hlapi/auth.py
+++ b/pysnmp/hlapi/auth.py
@@ -268,7 +268,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.
@@ -304,6 +306,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 58f3acc0..bfee07f9 100644
--- a/pysnmp/proto/mpmod/rfc3412.py
+++ b/pysnmp/proto/mpmod/rfc3412.py
@@ -203,31 +203,14 @@ class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel):
# 7.1.9.a
if pdu.tagSet in rfc3411.unconfirmedClassPDUs:
securityEngineId = snmpEngineID
+
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)
+ debug.logger & debug.flagMP and debug.logger(
+ 'prepareOutgoingMessage: peer SNMP engine is not known')
- # Use dead-empty PDU for engine-discovery report
- emptyPdu = pdu.clone()
- pMod.apiPDU.setDefaults(emptyPdu)
+ securityEngineId = None
- scopedPDU.getComponentByPosition(2).setComponentByType(
- emptyPdu.tagSet, emptyPdu, verifyConstraints=False, matchTags=False, matchConstraints=False
- )
- debug.logger & debug.flagMP and debug.logger('prepareOutgoingMessage: force engineID discovery')
else:
securityEngineId = peerSnmpEngineData['securityEngineId']
diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py
index ab125aa7..244e9324 100644
--- a/pysnmp/proto/secmod/rfc3414/service.py
+++ b/pysnmp/proto/secmod/rfc3414/service.py
@@ -13,13 +13,16 @@ from pysnmp.proto.secmod.rfc3826.priv import aes
from pysnmp.proto.secmod.rfc7860.auth import hmacsha2
from pysnmp.proto.secmod.eso.priv import des3, aes192, aes256
from pysnmp.smi.error import NoSuchInstanceError
-from pysnmp.proto import rfc1155, errind, error
+from pysnmp.proto import api, rfc1155, errind, error
from pysnmp import debug
from pyasn1.type import univ, namedtype, constraint
from pyasn1.codec.ber import encoder, decoder, eoo
from pyasn1.error import PyAsn1Error
from pyasn1.compat.octets import null
+# API to rfc1905 protocol objects
+pMod = api.protoModules[api.protoVersion2c]
+
# USM security params
@@ -224,6 +227,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel):
scopedPDU, securityStateReference):
mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder
snmpEngineID = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax
+ msg = globalData
# 3.1.1
if securityStateReference is not None:
@@ -271,7 +275,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel):
securityEngineID.prettyPrint(),
securityName, securityStateReference))
- elif securityName:
+ elif securityEngineID:
# 3.1.1b
try:
(usmUserName, usmUserSecurityName, usmUserAuthProtocol,
@@ -352,14 +356,43 @@ class SnmpUSMSecurityModel(AbstractSecurityModel):
)
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.serviceID
usmUserPrivProtocol = nopriv.NoPriv.serviceID
usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None
debug.logger & debug.flagSM and debug.logger(
- '__generateRequestOrResponseMsg: using blank USM info '
+ '__generateRequestOrResponseMsg: using blank USM info for peer '
+ 'SNMP engine ID discovery '
'usmUserName "%s" '
'usmUserSecurityName "%s" '
'usmUserAuthProtocol "%s" '
@@ -370,9 +403,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: