Hello community,

here is the log from the commit of package python-pysnmp for openSUSE:Factory 
checked in at 2019-09-11 10:36:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pysnmp (Old)
 and      /work/SRC/openSUSE:Factory/.python-pysnmp.new.7948 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pysnmp"

Wed Sep 11 10:36:33 2019 rev:14 rq:729835 version:4.4.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pysnmp/python-pysnmp.changes      
2019-08-05 10:36:27.439334026 +0200
+++ /work/SRC/openSUSE:Factory/.python-pysnmp.new.7948/python-pysnmp.changes    
2019-09-11 10:36:35.775275270 +0200
@@ -1,0 +2,9 @@
+Tue Sep 10 11:39:16 UTC 2019 - Tomáš Chvátal <tchva...@suse.com>
+
+- Update to 4.4.11:
+  - Added SNMPv3 USM master and localized keys support to LCD configuration
+  - Improved initial and runtime USM debugging
+  - Fixed a bug in USM configuration which did not allow the same user names
+    to be added under different security names
+
+-------------------------------------------------------------------

Old:
----
  pysnmp-4.4.10.tar.gz

New:
----
  pysnmp-4.4.11.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pysnmp.spec ++++++
--- /var/tmp/diff_new_pack.xWJsFq/_old  2019-09-11 10:36:36.187275150 +0200
+++ /var/tmp/diff_new_pack.xWJsFq/_new  2019-09-11 10:36:36.187275150 +0200
@@ -18,12 +18,12 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-pysnmp
-Version:        4.4.10
+Version:        4.4.11
 Release:        0
 Summary:        A pure-Python SNMPv1/v2c/v3 library
 License:        BSD-2-Clause
 Group:          Development/Languages/Python
-URL:            http://pysnmp.sourceforge.net/
+URL:            https://github.com/etingof/pysnmp
 Source:         
https://github.com/etingof/pysnmp/archive/v%{version}.tar.gz#/pysnmp-%{version}.tar.gz
 BuildRequires:  %{python_module pyasn1 >= 0.2.3}
 BuildRequires:  %{python_module pycryptodome}

++++++ pysnmp-4.4.10.tar.gz -> pysnmp-4.4.11.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/CHANGES.txt 
new/pysnmp-4.4.11/CHANGES.txt
--- old/pysnmp-4.4.10/CHANGES.txt       2019-07-30 20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/CHANGES.txt       2019-08-11 10:12:23.000000000 +0200
@@ -1,4 +1,12 @@
 
+Revision 4.4.11, released 2019-08-10
+------------------------------------
+
+- Added SNMPv3 USM master and localized keys support to LCD configuration
+- Improved initial and runtime USM debugging
+- Fixed a bug in USM configuration which did not allow the same user names
+  to be added under different security names
+
 Revision 4.4.10, released 2019-07-29
 ------------------------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/devel-requirements.txt 
new/pysnmp-4.4.11/devel-requirements.txt
--- old/pysnmp-4.4.10/devel-requirements.txt    2019-07-30 20:29:22.000000000 
+0200
+++ new/pysnmp-4.4.11/devel-requirements.txt    2019-08-11 10:12:23.000000000 
+0200
@@ -1,10 +1,16 @@
 Sphinx <= 1.6; python_version < '2.7'
 Sphinx > 1.6; python_version >= '2.7'
 trollius; python_version < '3.0'
+# NOTE: Twisted < 19.2.1 has a security problem in URL handling.
+# However, newer Twisted does not work on older Pythons. That's why
+# we have to pin to older Twisted here.
+# On the other hand, pysnmp does not use anything HTTP, however other
+# dependencies can rely on that.
 twisted < 15.4; python_version < '2.7'
 twisted; python_version == '2.7'
 twisted < 17.9; python_version == '3.0'
 twisted < 17.9; python_version == '3.1'
 twisted < 17.9; python_version == '3.2'
 twisted <= 17.9; python_version == '3.3'
-twisted; python_version >= '3.4'
+twisted <= 17.9; python_version == '3.4'
+twisted; python_version >= '3.5'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/docs/mibs/PYSNMP-USM-MIB.txt 
new/pysnmp-4.4.11/docs/mibs/PYSNMP-USM-MIB.txt
--- old/pysnmp-4.4.10/docs/mibs/PYSNMP-USM-MIB.txt      2019-07-30 
20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/docs/mibs/PYSNMP-USM-MIB.txt      2019-08-11 
10:12:23.000000000 +0200
@@ -21,6 +21,8 @@
     DESCRIPTION
         "This MIB module defines objects specific to User
          Security Model (USM) implementation at PySNMP."
+    REVISION    "201908300000Z"
+    DESCRIPTION "Added USM key types"
     REVISION    "201707300000Z"
     DESCRIPTION "Extended authentication key size"
     REVISION    "201704140000Z"
@@ -56,6 +58,19 @@
     DEFVAL      { doDiscover }
     ::= { pysnmpUsmCfg 2 }
 
+pysnmpUsmKeyType OBJECT-TYPE
+    SYNTAX       INTEGER { passphrase (0), master(1), localized(2) }
+    MAX-ACCESS   not-accessible
+    STATUS       current
+    DESCRIPTION "When configuring USM user, the value of this enumeration
+                 determines how the keys should be treated. The default
+                 value "passphrase" means that given keys are plain-text
+                 pass-phrases, "master" indicates that the keys are pre-hashed
+                 pass-phrases, while "localized" stands for pre-hashed
+                 pass-phrases mixed with SNMP Security Engine ID value."
+    DEFVAL      { passphrase }
+    ::= { pysnmpUsmCfg 3 }
+
 -- The usmUser Group ************************************************
 
 pysnmpUsmUser       OBJECT IDENTIFIER ::= { pysnmpUsmMIBObjects 3 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/docs/source/docs/api-reference.rst 
new/pysnmp-4.4.11/docs/source/docs/api-reference.rst
--- old/pysnmp-4.4.10/docs/source/docs/api-reference.rst        2019-07-30 
20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/docs/source/docs/api-reference.rst        2019-08-11 
10:12:23.000000000 +0200
@@ -217,7 +217,7 @@
 The :py:class:`~pysnmp.hlapi.UsmUserData` class provides SNMPv3 User-Based
 Security Model configuration for SNMP v3 systems.
 
-.. autoclass:: pysnmp.hlapi.UsmUserData(userName, authKey=None, privKey=None, 
authProtocol=usmNoAuthProtocol, privProtocol=usmNoPrivProtocol, 
securityEngineId=None)
+.. autoclass:: pysnmp.hlapi.UsmUserData(userName, authKey=None, privKey=None, 
authProtocol=usmNoAuthProtocol, privProtocol=usmNoPrivProtocol, 
securityEngineId=None, authKeyType=usmKeyTypePassphrase, 
privKeyType=usmKeyTypePassphrase)
 
 **Authentication protocol identifiers**
 
@@ -240,10 +240,16 @@
 .. autodata:: pysnmp.hlapi.usmAesBlumenthalCfb192Protocol
 .. autodata:: pysnmp.hlapi.usmAesBlumenthalCfb256Protocol
 
+**Key material types**
+
+.. autodata:: pysnmp.hlapi.usmKeyTypePassphrase
+.. autodata:: pysnmp.hlapi.usmKeyTypeMaster
+.. autodata:: pysnmp.hlapi.usmKeyTypeLocalized
+
 .. note::
 
-   SNMP authentication and encryption keys must be at least *eight*
-   octets long.
+   SNMP authentication and encryption keys must be at least *8*
+   and at most *32* octets long.
 
 Transport configuration is I/O framework specific and is described in
 respective sections.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pysnmp-4.4.10/examples/v3arch/asyncore/agent/cmdrsp/multiple-usm-users.py 
new/pysnmp-4.4.11/examples/v3arch/asyncore/agent/cmdrsp/multiple-usm-users.py
--- 
old/pysnmp-4.4.10/examples/v3arch/asyncore/agent/cmdrsp/multiple-usm-users.py   
    2019-07-30 20:29:22.000000000 +0200
+++ 
new/pysnmp-4.4.11/examples/v3arch/asyncore/agent/cmdrsp/multiple-usm-users.py   
    2019-08-11 10:12:23.000000000 +0200
@@ -32,7 +32,7 @@
 config.addTransport(
     snmpEngine,
     udp.domainName,
-    udp.UdpTransport().openServerMode(('127.0.0.1', 161))
+    udp.UdpTransport().openServerMode(('127.0.0.1', 1161))
 )
 
 # SNMPv3/USM setup
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/__init__.py 
new/pysnmp-4.4.11/pysnmp/__init__.py
--- old/pysnmp-4.4.10/pysnmp/__init__.py        2019-07-30 20:29:22.000000000 
+0200
+++ new/pysnmp-4.4.11/pysnmp/__init__.py        2019-08-11 10:12:23.000000000 
+0200
@@ -1,5 +1,5 @@
 # http://www.python.org/dev/peps/pep-0396/
-__version__ = '4.4.10'
+__version__ = '4.4.11'
 # backward compatibility
 version = tuple([int(x) for x in __version__.split('.')])
 majorVersionId = version[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/entity/config.py 
new/pysnmp-4.4.11/pysnmp/entity/config.py
--- old/pysnmp-4.4.10/pysnmp/entity/config.py   2019-07-30 20:29:22.000000000 
+0200
+++ new/pysnmp-4.4.11/pysnmp/entity/config.py   2019-08-11 10:12:23.000000000 
+0200
@@ -14,6 +14,7 @@
 from pysnmp.proto import rfc1902
 from pysnmp.proto import rfc1905
 from pysnmp import error
+from pysnmp import debug
 
 # A shortcut to popular constants
 
@@ -43,6 +44,11 @@
 usmAesCfb256Protocol = aes256.Aes256.serviceID  # non-standard but used by 
many vendors
 usmNoPrivProtocol = nopriv.NoPriv.serviceID
 
+# USM key types (PYSNMP-USM-MIB::pysnmpUsmKeyType)
+usmKeyTypePassphrase = 0
+usmKeyTypeMaster = 1
+usmKeyTypeLocalized = 2
+
 # Auth services
 authServices = {hmacmd5.HmacMd5.serviceID: hmacmd5.HmacMd5(),
                 hmacsha.HmacSha.serviceID: hmacsha.HmacSha(),
@@ -86,13 +92,15 @@
     if contextName is None:
         contextName = null
 
+    securityName = securityName is not None and securityName or communityIndex
+
     snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
         ((snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'),)
     )
     snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
         ((snmpCommunityEntry.name + (1,) + tblIdx, communityIndex),
          (snmpCommunityEntry.name + (2,) + tblIdx, communityName),
-         (snmpCommunityEntry.name + (3,) + tblIdx, securityName is not None 
and securityName or communityIndex),
+         (snmpCommunityEntry.name + (3,) + tblIdx, securityName),
          (snmpCommunityEntry.name + (4,) + tblIdx, contextEngineId),
          (snmpCommunityEntry.name + (5,) + tblIdx, contextName),
          (snmpCommunityEntry.name + (6,) + tblIdx, transportTag),
@@ -100,6 +108,13 @@
          (snmpCommunityEntry.name + (8,) + tblIdx, 'createAndGo'))
     )
 
+    debug.logger & debug.flagSM and debug.logger(
+        'addV1System: added new table entry '
+        'communityIndex "%s" communityName "%s" securityName "%s" '
+        'contextEngineId "%s" contextName "%s" transportTag '
+        '"%s"' % (communityIndex, communityName, securityName,
+                  contextEngineId, contextName, transportTag))
+
 
 def delV1System(snmpEngine, communityIndex):
     (snmpCommunityEntry, tblIdx,
@@ -108,6 +123,10 @@
         ((snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'),)
     )
 
+    debug.logger & debug.flagSM and debug.logger(
+        'delV1System: deleted table entry by communityIndex '
+        '"%s"' % (communityIndex,))
+
 
 def __cookV3UserInfo(snmpEngine, securityName, securityEngineId):
     mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder
@@ -115,17 +134,17 @@
     snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 
'snmpEngineID')
 
     if securityEngineId is None:
-        snmpEngineID = snmpEngineID.syntax
+        securityEngineId = snmpEngineID.syntax
     else:
-        snmpEngineID = snmpEngineID.syntax.clone(securityEngineId)
+        securityEngineId = snmpEngineID.syntax.clone(securityEngineId)
 
     usmUserEntry, = mibBuilder.importSymbols('SNMP-USER-BASED-SM-MIB', 
'usmUserEntry')
-    tblIdx1 = usmUserEntry.getInstIdFromIndices(snmpEngineID, securityName)
+    tblIdx1 = usmUserEntry.getInstIdFromIndices(securityEngineId, securityName)
 
     pysnmpUsmSecretEntry, = mibBuilder.importSymbols('PYSNMP-USM-MIB', 
'pysnmpUsmSecretEntry')
     tblIdx2 = pysnmpUsmSecretEntry.getInstIdFromIndices(securityName)
 
-    return snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2
+    return securityEngineId, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, 
tblIdx2
 
 
 def addV3User(snmpEngine, userName,
@@ -133,16 +152,22 @@
               privProtocol=usmNoPrivProtocol, privKey=None,
               securityEngineId=None,
               securityName=None,
-              # deprecated parameters follow
+              authKeyType=usmKeyTypePassphrase,
+              privKeyType=usmKeyTypePassphrase,
+              # deprecated parameter
               contextEngineId=None):
+
     mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder
 
     if securityName is None:
         securityName = userName
+
     if securityEngineId is None:  # backward compatibility
         securityEngineId = contextEngineId
-    (snmpEngineID, usmUserEntry, tblIdx1,
-     pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo(snmpEngine, userName, 
securityEngineId)
+
+    (securityEngineId, usmUserEntry, tblIdx1,
+     pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo(
+        snmpEngine, securityName, securityEngineId)
 
     # Load augmenting table before creating new row in base one
     pysnmpUsmKeyEntry, = mibBuilder.importSymbols('PYSNMP-USM-MIB', 
'pysnmpUsmKeyEntry')
@@ -162,47 +187,109 @@
          (usmUserEntry.name + (13,) + tblIdx1, 'createAndGo'))
     )
 
-    # Localize keys
-    if authProtocol in authServices:
-        hashedAuthPassphrase = authServices[authProtocol].hashPassphrase(
-            authKey and authKey or null
+    if authProtocol not in authServices:
+        raise error.PySnmpError('Unknown auth protocol %s' % (authProtocol,))
+
+    if privProtocol not in privServices:
+        raise error.PySnmpError('Unknown privacy protocol %s' % 
(privProtocol,))
+
+    pysnmpUsmKeyType, = mibBuilder.importSymbols('__PYSNMP-USM-MIB', 
'pysnmpUsmKeyType')
+
+    authKeyType = pysnmpUsmKeyType.syntax.clone(authKeyType)
+
+    # Localize authentication key unless given
+
+    authKey = authKey and rfc1902.OctetString(authKey)
+
+    masterAuthKey = localAuthKey = authKey
+
+    if authKeyType < usmKeyTypeMaster:  # pass phrase is given
+        masterAuthKey = authServices[authProtocol].hashPassphrase(
+            authKey or null
         )
+
+    if authKeyType < usmKeyTypeLocalized:  # pass phrase or master key is given
         localAuthKey = authServices[authProtocol].localizeKey(
-            hashedAuthPassphrase, snmpEngineID
+            masterAuthKey, securityEngineId
         )
-    else:
-        raise error.PySnmpError('Unknown auth protocol %s' % (authProtocol,))
 
-    if privProtocol in privServices:
-        hashedPrivPassphrase = privServices[privProtocol].hashPassphrase(
-            authProtocol, privKey and privKey or null
+    # Localize privacy key unless given
+
+    privKeyType = pysnmpUsmKeyType.syntax.clone(privKeyType)
+
+    privKey = privKey and rfc1902.OctetString(privKey)
+
+    masterPrivKey = localPrivKey = privKey
+
+    if privKeyType < usmKeyTypeMaster:  # pass phrase is given
+        masterPrivKey = privServices[privProtocol].hashPassphrase(
+            authProtocol, privKey or null
         )
+
+    if privKeyType < usmKeyTypeLocalized:  # pass phrase or master key is given
         localPrivKey = privServices[privProtocol].localizeKey(
-            authProtocol, hashedPrivPassphrase, snmpEngineID
+            authProtocol, masterPrivKey, securityEngineId
         )
-    else:
-        raise error.PySnmpError('Unknown priv protocol %s' % (privProtocol,))
 
-    # Commit localized keys
+    # Commit only the keys we have
+
     snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
-        ((pysnmpUsmKeyEntry.name + (1,) + tblIdx1, localAuthKey),
-         (pysnmpUsmKeyEntry.name + (2,) + tblIdx1, localPrivKey),
-         (pysnmpUsmKeyEntry.name + (3,) + tblIdx1, hashedAuthPassphrase),
-         (pysnmpUsmKeyEntry.name + (4,) + tblIdx1, hashedPrivPassphrase))
+        ((pysnmpUsmKeyEntry.name + (1,) + tblIdx1, localAuthKey),)
     )
 
-    # Commit passphrases
+    snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
+        ((pysnmpUsmKeyEntry.name + (2,) + tblIdx1, localPrivKey),)
+    )
+
+    if authKeyType < usmKeyTypeLocalized:
+        snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
+            ((pysnmpUsmKeyEntry.name + (3,) + tblIdx1, masterAuthKey),)
+        )
+
+    if privKeyType < usmKeyTypeLocalized:
+        snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
+            ((pysnmpUsmKeyEntry.name + (4,) + tblIdx1, masterPrivKey),)
+        )
 
     snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
         ((pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'),)
     )
+
+    # Commit plain-text pass-phrases if we have them
+
     snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
-        ((pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName),
-         (pysnmpUsmSecretEntry.name + (2,) + tblIdx2, authKey),
-         (pysnmpUsmSecretEntry.name + (3,) + tblIdx2, privKey),
-         (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'createAndGo'))
+        ((pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'createAndGo'),)
     )
 
+    if authKeyType < usmKeyTypeMaster:
+        snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
+            ((pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName),
+             (pysnmpUsmSecretEntry.name + (2,) + tblIdx2, authKey))
+        )
+
+    if privKeyType < usmKeyTypeMaster:
+        snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
+            ((pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName),
+             (pysnmpUsmSecretEntry.name + (3,) + tblIdx2, privKey))
+        )
+
+    debug.logger & debug.flagSM and debug.logger(
+        'addV3User: added new table entries '
+        'userName "%s" securityName "%s" authProtocol %s '
+        'privProtocol %s localAuthKey "%s" localPrivKey "%s" '
+        'masterAuthKey "%s" masterPrivKey "%s" authKey "%s" '
+        'privKey "%s" by index securityName "%s" securityEngineId '
+        '"%s"' % (
+            userName, securityName, authProtocol, privProtocol,
+            localAuthKey and localAuthKey.prettyPrint(),
+            localPrivKey and localPrivKey.prettyPrint(),
+            masterAuthKey and masterAuthKey.prettyPrint(),
+            masterPrivKey and masterPrivKey.prettyPrint(),
+            authKey and authKey.prettyPrint(),
+            privKey and privKey.prettyPrint(),
+            securityName,
+            securityEngineId.prettyPrint()))
+
 
 def delV3User(snmpEngine,
               userName,
@@ -211,21 +298,31 @@
               contextEngineId=None):
     if securityEngineId is None:  # backward compatibility
         securityEngineId = contextEngineId
-    (snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry,
+    (securityEngineId, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry,
      tblIdx2) = __cookV3UserInfo(snmpEngine, userName, securityEngineId)
+
     snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
         ((usmUserEntry.name + (13,) + tblIdx1, 'destroy'),)
     )
+
     snmpEngine.msgAndPduDsp.mibInstrumController.writeVars(
         ((pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'),)
     )
 
+    debug.logger & debug.flagSM and debug.logger(
+        'delV3User: deleted table entries by index '
+        'userName "%s" securityEngineId '
+        '"%s"' % (
+            userName,
+            securityEngineId.prettyPrint()))
+
     # Drop all derived rows
     varBinds = initialVarBinds = (
         (usmUserEntry.name + (1,), None),  # usmUserEngineID
         (usmUserEntry.name + (2,), None),  # usmUserName
         (usmUserEntry.name + (4,), None)  # usmUserCloneFrom
     )
+
     while varBinds:
         varBinds = snmpEngine.msgAndPduDsp.mibInstrumController.readNextVars(
             varBinds
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/hlapi/__init__.py 
new/pysnmp-4.4.11/pysnmp/hlapi/__init__.py
--- old/pysnmp-4.4.10/pysnmp/hlapi/__init__.py  2019-07-30 20:29:22.000000000 
+0200
+++ new/pysnmp-4.4.11/pysnmp/hlapi/__init__.py  2019-08-11 10:12:23.000000000 
+0200
@@ -62,3 +62,13 @@
 
 usmAesBlumenthalCfb256Protocol = auth.usmAesBlumenthalCfb256Protocol
 """The CFB128-AES-256 Symmetric Encryption Protocol 
(`draft-blumenthal-aes-usm-04 
<https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)"""
+
+usmKeyTypePassphrase = auth.usmKeyTypePassphrase
+"""USM key material type - plain-text pass phrase (:RFC:`3414#section-2.6`)"""
+
+usmKeyTypeMaster = auth.usmKeyTypeMaster
+"""USM key material type - hashed pass-phrase AKA master key 
(:RFC:`3414#section-2.6`)"""
+
+usmKeyTypeLocalized = auth.usmKeyTypeLocalized
+"""USM key material type - hashed pass-phrase hashed with Context SNMP Engine 
ID (:RFC:`3414#section-2.6`)"""
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/hlapi/auth.py 
new/pysnmp-4.4.11/pysnmp/hlapi/auth.py
--- old/pysnmp-4.4.10/pysnmp/hlapi/auth.py      2019-07-30 20:29:22.000000000 
+0200
+++ new/pysnmp-4.4.11/pysnmp/hlapi/auth.py      2019-08-11 10:12:23.000000000 
+0200
@@ -34,21 +34,30 @@
 
     Parameters
     ----------
-    communityIndex: py:class:`str`
+    communityIndex: :py:class:`str`, 
:py:class:`~pysnmp.proto.rfc1902.OctetString`
         Unique index value of a row in snmpCommunityTable. If it is the
         only positional parameter, it is treated as a *communityName*.
-    communityName: py:class:`str`
+
+    communityName: :py:class:`str`, 
:py:class:`~pysnmp.proto.rfc1902.OctetString`
         SNMP v1/v2c community string.
-    mpModel: py:class:`int`
-        SNMP version - 0 for SNMPv1 and 1 for SNMPv2c.
-    contextEngineId: py:class:`str`
+
+    mpModel: :py:class:`int`
+        SNMP message processing model AKA SNMP version. Known SNMP versions 
are:
+
+        * `0` - for SNMP v1
+        * `1` - for SNMP v2c (default)
+
+
+    contextEngineId: :py:class:`str`, 
:py:class:`~pysnmp.proto.rfc1902.OctetString`
         Indicates the location of the context in which management
         information is accessed when using the community string
         specified by the above communityName.
-    contextName: py:class:`str`
+
+    contextName: :py:class:`str`, :py:class:`~pysnmp.proto.rfc1902.OctetString`
         The context in which management information is accessed when
         using the above communityName.
-    tag: py:class:`str`
+
+    tag: :py:class:`str`
         Arbitrary string that specifies a set of transport endpoints
         from which a command responder application will accept
         management requests with given *communityName* or to which
@@ -196,6 +205,15 @@
 usmAesBlumenthalCfb256Protocol = config.usmAesBlumenthalCfb256Protocol
 """The CFB128-AES-256 Symmetric Encryption Protocol 
(`draft-blumenthal-aes-usm-04 
<https:://tools.ietf.org/html/draft-blumenthal-aes-usm-04#section-3>`_)"""
 
+usmKeyTypePassphrase = config.usmKeyTypePassphrase
+"""USM key material type - plain-text pass phrase (:RFC:`3414#section-2.6`)"""
+
+usmKeyTypeMaster = config.usmKeyTypeMaster
+"""USM key material type - hashed pass-phrase AKA master key 
(:RFC:`3414#section-2.6`)"""
+
+usmKeyTypeLocalized = config.usmKeyTypeLocalized
+"""USM key material type - hashed pass-phrase hashed with Context SNMP Engine 
ID (:RFC:`3414#section-2.6`)"""
+
 
 class UsmUserData(object):
     """Creates SNMP v3 User Security Model (USM) configuration entry.
@@ -212,21 +230,26 @@
 
     Parameters
     ----------
-    userName: py:class:`str`
+    userName: :py:class:`str`, :py:class:`~pysnmp.proto.rfc1902.OctetString`
         A human readable string representing the name of the SNMP USM user.
-    authKey: py:class:`str`
+
+    Other Parameters
+    ----------------
+    authKey: :py:class:`str`, :py:class:`~pysnmp.proto.rfc1902.OctetString`
         Initial value of the secret authentication key.  If not set,
         :py:class:`~pysnmp.hlapi.usmNoAuthProtocol`
         is implied.  If set and no *authProtocol* is specified,
         :py:class:`~pysnmp.hlapi.usmHMACMD5AuthProtocol`
         takes effect.
-    privKey: py:class:`str`
+
+    privKey: :py:class:`str`, :py:class:`~pysnmp.proto.rfc1902.OctetString`
         Initial value of the secret encryption key.  If not set,
         :py:class:`~pysnmp.hlapi.usmNoPrivProtocol`
         is implied.  If set and no *privProtocol* is specified,
         :py:class:`~pysnmp.hlapi.usmDESPrivProtocol`
         takes effect.
-    authProtocol: py:class:`tuple`
+
+    authProtocol: :py:class:`tuple`, 
:py:class:`~pysnmp.proto.rfc1902.ObjectIdentifier`
         An indication of whether messages sent on behalf of this USM user
         can be authenticated, and if so, the type of authentication protocol
         which is used.
@@ -240,7 +263,25 @@
         * :py:class:`~pysnmp.hlapi.usmHMAC192SHA256AuthProtocol`
         * :py:class:`~pysnmp.hlapi.usmHMAC256SHA384AuthProtocol`
         * :py:class:`~pysnmp.hlapi.usmHMAC384SHA512AuthProtocol`
-    privProtocol: py:class:`tuple`
+
+
+    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, unless localized keys
+        are used. In the latter case *securityEngineId* must be
+        specified.
+
+        See :RFC:`3414#section-2.5.1` for technical explanation.
+
+    securityName: :py:class:`str`, 
:py:class:`~pysnmp.proto.rfc1902.OctetString`
+        Together with the snmpEngineID it identifies a row in the
+        *SNMP-USER-BASED-SM-MIB::usmUserTable* that is to be used
+        for securing the message.
+
+        See :RFC:`3414#section-2.5.1` for technical explanation.
+
+    privProtocol: :py:class:`tuple`, 
:py:class:`~pysnmp.proto.rfc1902.ObjectIdentifier`
         An indication of whether messages sent on behalf of this USM user
         be encrypted, and if so, the type of encryption protocol which is used.
 
@@ -253,6 +294,43 @@
         * :py:class:`~pysnmp.hlapi.usmAesCfb192Protocol`
         * :py:class:`~pysnmp.hlapi.usmAesCfb256Protocol`
 
+
+    authKeyType: :py:class:`int`
+        Type of `authKey` material. See :RFC:`3414#section-2.6` for
+        technical explanation.
+
+        Supported key types are:
+
+        * :py:class:`~pysnmp.hlapi.usmKeyTypePassphrase` (default)
+        * :py:class:`~pysnmp.hlapi.usmKeyTypeMaster`
+        * :py:class:`~pysnmp.hlapi.usmKeyTypeLocalized`
+
+    privKeyType: :py:class:`int`
+        Type of `privKey` material. See :RFC:`3414#section-2.6` for
+        technical explanation.
+
+        Supported key types are:
+
+        * :py:class:`~pysnmp.hlapi.usmKeyTypePassphrase` (default)
+        * :py:class:`~pysnmp.hlapi.usmKeyTypeMaster`
+        * :py:class:`~pysnmp.hlapi.usmKeyTypeLocalized`
+
+    Notes
+    -----
+    If `~pysnmp.hlapi.usmKeyTypeLocalized` is used when running a
+    non-authoritative SNMP engine, USM key localization mechanism
+    is not invoked. As a consequence, local SNMP engine configuration
+    won't get automatically populated with remote SNMP engine's
+    *securityEngineId*.
+
+    Therefore peer SNMP engine's *securityEngineId* must be added
+    to local configuration and associated with its localized keys.
+
+    Alternatively, the magic *securityEngineId* value of five zeros
+    (*0x0000000000*) can be used to refer to the localized keys that
+    should be used with any unknown remote SNMP engine. This feature
+    is specific to pysnmp.
+
     Examples
     --------
     >>> from pysnmp.hlapi import UsmUserData
@@ -275,7 +353,9 @@
                  authKey=None, privKey=None,
                  authProtocol=None, privProtocol=None,
                  securityEngineId=None,
-                 securityName=None):
+                 securityName=None,
+                 authKeyType=usmKeyTypePassphrase,
+                 privKeyType=usmKeyTypePassphrase):
         self.userName = userName
         if securityName is None:
             self.securityName = userName
@@ -302,24 +382,29 @@
                 self.privProtocol = privProtocol
 
         self.securityEngineId = securityEngineId
+        self.authKeyType = authKeyType
+        self.privKeyType = privKeyType
 
     def __hash__(self):
         raise TypeError('%s is not hashable' % self.__class__.__name__)
 
     def __repr__(self):
-        return '%s(userName=%r, authKey=<AUTHKEY>, privKey=<PRIVKEY>, 
authProtocol=%r, privProtocol=%r, securityEngineId=%r, securityName=%r)' % (
+        return '%s(userName=%r, authKey=<AUTHKEY>, privKey=<PRIVKEY>, 
authProtocol=%r, privProtocol=%r, securityEngineId=%r, securityName=%r, 
authKeyType=%r, privKeyType=%r)' % (
             self.__class__.__name__,
             self.userName,
             self.authProtocol,
             self.privProtocol,
             self.securityEngineId is None and '<DEFAULT>' or 
self.securityEngineId,
-            self.securityName
+            self.securityName,
+            self.authKeyType,
+            self.privKeyType
         )
 
     def clone(self, userName=None,
               authKey=None, privKey=None,
               authProtocol=None, privProtocol=None,
-              securityEngineId=None, securityName=None):
+              securityEngineId=None, securityName=None,
+              authKeyType=None, privKeyType=None):
         return self.__class__(
             userName is None and self.userName or userName,
             authKey is None and self.authKey or authKey,
@@ -327,5 +412,7 @@
             authProtocol is None and self.authProtocol or authProtocol,
             privProtocol is None and self.privProtocol or privProtocol,
             securityEngineId is None and self.securityEngineId or 
securityEngineId,
-            securityName=securityName is None and self.securityName or 
securityName
+            securityName is None and self.securityName or securityName,
+            authKeyType is None and self.authKeyType or usmKeyTypePassphrase,
+            privKeyType is None and self.privKeyType or usmKeyTypePassphrase
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/hlapi/lcd.py 
new/pysnmp-4.4.11/pysnmp/hlapi/lcd.py
--- old/pysnmp-4.4.10/pysnmp/hlapi/lcd.py       2019-07-30 20:29:22.000000000 
+0200
+++ new/pysnmp-4.4.11/pysnmp/hlapi/lcd.py       2019-08-11 10:12:23.000000000 
+0200
@@ -58,8 +58,10 @@
                     authData.userName,
                     authData.authProtocol, authData.authKey,
                     authData.privProtocol, authData.privKey,
-                    authData.securityEngineId,
-                    securityName=authData.securityName
+                    securityEngineId=authData.securityEngineId,
+                    securityName=authData.securityName,
+                    authKeyType=authData.authKeyType,
+                    privKeyType=authData.privKeyType
                 )
                 cache['auth'][authDataKey] = authData
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/proto/mpmod/rfc3412.py 
new/pysnmp-4.4.11/pysnmp/proto/mpmod/rfc3412.py
--- old/pysnmp-4.4.10/pysnmp/proto/mpmod/rfc3412.py     2019-07-30 
20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/pysnmp/proto/mpmod/rfc3412.py     2019-08-11 
10:12:23.000000000 +0200
@@ -203,31 +203,14 @@
         # 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pysnmp-4.4.10/pysnmp/proto/secmod/eso/priv/aesbase.py 
new/pysnmp-4.4.11/pysnmp/proto/secmod/eso/priv/aesbase.py
--- old/pysnmp-4.4.10/pysnmp/proto/secmod/eso/priv/aesbase.py   2019-07-30 
20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/pysnmp/proto/secmod/eso/priv/aesbase.py   2019-08-11 
10:12:23.000000000 +0200
@@ -42,7 +42,8 @@
 
         # now extend this key if too short by repeating steps that includes 
the hashPassphrase step
         for count in range(1, int(ceil(self.keySize * 1.0 / 
len(localPrivKey)))):
-            localPrivKey += hashAlgo(localPrivKey).digest()
+            localPrivKey += localPrivKey.clone(
+                hashAlgo(localPrivKey.asOctets()).digest())
 
         return localPrivKey[:self.keySize]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pysnmp-4.4.10/pysnmp/proto/secmod/rfc3414/localkey.py 
new/pysnmp-4.4.11/pysnmp/proto/secmod/rfc3414/localkey.py
--- old/pysnmp-4.4.10/pysnmp/proto/secmod/rfc3414/localkey.py   2019-07-30 
20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/pysnmp/proto/secmod/rfc3414/localkey.py   2019-08-11 
10:12:23.000000000 +0200
@@ -37,7 +37,8 @@
             )
             mark = e - ringBufferLen
         count += 1
-    return hasher.digest()
+    digest = hasher.digest()
+    return univ.OctetString(digest)
 
 
 def passwordToKey(passphrase, snmpEngineId, hashFunc):
@@ -47,7 +48,8 @@
 def localizeKey(passKey, snmpEngineId, hashFunc):
     passKey = univ.OctetString(passKey).asOctets()
     # noinspection PyDeprecation,PyCallingNonCallable
-    return hashFunc(passKey + snmpEngineId.asOctets() + passKey).digest()
+    digest = hashFunc(passKey + snmpEngineId.asOctets() + passKey).digest()
+    return univ.OctetString(digest)
 
 
 # RFC3414: A.2.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/proto/secmod/rfc3414/service.py 
new/pysnmp-4.4.11/pysnmp/proto/secmod/rfc3414/service.py
--- old/pysnmp-4.4.10/pysnmp/proto/secmod/rfc3414/service.py    2019-07-30 
20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/pysnmp/proto/secmod/rfc3414/service.py    2019-08-11 
10:12:23.000000000 +0200
@@ -13,13 +13,16 @@
 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
 
@@ -56,6 +59,11 @@
                     aes256.Aes256.serviceID: aes256.Aes256(),  # non-standard
                     nopriv.NoPriv.serviceID: nopriv.NoPriv()}
 
+    # If this, normally impossible, SNMP engine ID is present in LCD, we will 
use
+    # its master/localized keys when preparing SNMP message towards any 
unknown peer
+    # SNMP engine
+    wildcardSecurityEngineId = pMod.OctetString(hexValue='0000000000')
+
     def __init__(self):
         AbstractSecurityModel.__init__(self)
         self.__securityParametersSpec = UsmSecurityParameters()
@@ -224,6 +232,7 @@
                                        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:
@@ -250,19 +259,66 @@
                 usmUserPrivKeyLocalized = 
cachedSecurityData['usmUserPrivKeyLocalized']
             else:
                 usmUserPrivKeyLocalized = None
+
             securityEngineID = snmpEngineID
-            debug.logger & debug.flagSM and 
debug.logger('__generateRequestOrResponseMsg: user info read from cache')
-        elif securityName:
+
+            debug.logger & debug.flagSM and debug.logger(
+                '__generateRequestOrResponseMsg: using cached USM user entry '
+                'usmUserName "%s" '
+                'usmUserSecurityName "%s" '
+                'usmUserAuthProtocol "%s" '
+                'usmUserAuthKeyLocalized "%s" '
+                'usmUserPrivProtocol "%s" '
+                'usmUserPrivKeyLocalized "%s" for '
+                'securityEngineID "%s" and  securityName "%s" found by '
+                'securityStateReference "%s" ' % (
+                    usmUserName, usmUserSecurityName,
+                    usmUserAuthProtocol,
+                    usmUserAuthKeyLocalized and 
usmUserAuthKeyLocalized.prettyPrint(),
+                    usmUserPrivProtocol,
+                    usmUserPrivKeyLocalized and 
usmUserPrivKeyLocalized.prettyPrint(),
+                    securityEngineID.prettyPrint(),
+                    securityName, securityStateReference))
+
+        elif securityEngineID:
             # 3.1.1b
             try:
-                (usmUserName, usmUserSecurityName, usmUserAuthProtocol,
-                 usmUserAuthKeyLocalized, usmUserPrivProtocol,
-                 usmUserPrivKeyLocalized) = self.__getUserInfo(
-                    snmpEngine.msgAndPduDsp.mibInstrumController,
-                    securityEngineID,
-                    self.__sec2usr(snmpEngine, securityName, securityEngineID)
-                )
-                debug.logger & debug.flagSM and 
debug.logger('__generateRequestOrResponseMsg: read user info')
+                try:
+                    (usmUserName, usmUserSecurityName, usmUserAuthProtocol,
+                     usmUserAuthKeyLocalized, usmUserPrivProtocol,
+                     usmUserPrivKeyLocalized) = self.__getUserInfo(
+                        snmpEngine.msgAndPduDsp.mibInstrumController,
+                        securityEngineID,
+                        self.__sec2usr(snmpEngine, securityName,
+                                       securityEngineID)
+                    )
+
+                except NoSuchInstanceError:
+                    (usmUserName, usmUserSecurityName, usmUserAuthProtocol,
+                     usmUserAuthKeyLocalized, usmUserPrivProtocol,
+                     usmUserPrivKeyLocalized) = self.__getUserInfo(
+                        snmpEngine.msgAndPduDsp.mibInstrumController,
+                        self.wildcardSecurityEngineId,
+                        self.__sec2usr(snmpEngine, securityName,
+                                       self.wildcardSecurityEngineId)
+                    )
+
+                debug.logger & debug.flagSM and debug.logger(
+                    '__generateRequestOrResponseMsg: found USM user entry '
+                    'usmUserName "%s" '
+                    'usmUserSecurityName "%s" '
+                    'usmUserAuthProtocol "%s" '
+                    'usmUserAuthKeyLocalized "%s" '
+                    'usmUserPrivProtocol "%s" '
+                    'usmUserPrivKeyLocalized "%s" by '
+                    'securityEngineID "%s" and  securityName "%s"' % (
+                        usmUserName, usmUserSecurityName,
+                        usmUserAuthProtocol,
+                        usmUserAuthKeyLocalized and 
usmUserAuthKeyLocalized.prettyPrint(),
+                        usmUserPrivProtocol,
+                        usmUserPrivKeyLocalized and 
usmUserPrivKeyLocalized.prettyPrint(),
+                        securityEngineID.prettyPrint(),
+                        securityName))
 
             except NoSuchInstanceError:
                 pysnmpUsmDiscovery, = 
mibBuilder.importSymbols('__PYSNMP-USM-MIB', 'pysnmpUsmDiscovery')
@@ -278,7 +334,28 @@
                             self.__sec2usr(snmpEngine, securityName)
                         )
 
+                        debug.logger & debug.flagSM and debug.logger(
+                            '__generateRequestOrResponseMsg: cloned USM user 
entry '
+                            'usmUserName "%s" '
+                            'usmUserSecurityName "%s" '
+                            'usmUserAuthProtocol "%s" '
+                            'usmUserAuthKeyLocalized "%s" '
+                            'usmUserPrivProtocol "%s" '
+                            'usmUserPrivKeyLocalized "%s" for '
+                            'securityEngineID "%s" and  securityName "%s"' % (
+                                usmUserName, usmUserSecurityName,
+                                usmUserAuthProtocol,
+                                usmUserAuthKeyLocalized and 
usmUserAuthKeyLocalized.prettyPrint(),
+                                usmUserPrivProtocol,
+                                usmUserPrivKeyLocalized and 
usmUserPrivKeyLocalized.prettyPrint(),
+                                securityEngineID.prettyPrint(), securityName))
+
                     except NoSuchInstanceError:
+                        debug.logger & debug.flagSM and debug.logger(
+                            '__generateRequestOrResponseMsg: failed to clone '
+                            'USM user for securityEngineID "%s" securityName '
+                            '"%s"' % (securityEngineID, securityName))
+
                         reportUnknownName = True
 
                 if reportUnknownName:
@@ -286,8 +363,6 @@
                         errorIndication=errind.unknownSecurityName
                     )
 
-                debug.logger & debug.flagSM and 
debug.logger('__generateRequestOrResponseMsg: clone user info')
-
             except PyAsn1Error:
                 debug.logger & debug.flagSM and debug.logger(
                     '__generateRequestOrResponseMsg: %s' % 
(sys.exc_info()[1],))
@@ -296,20 +371,57 @@
                 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.serviceID
             usmUserPrivProtocol = nopriv.NoPriv.serviceID
             usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None
-            debug.logger & debug.flagSM and 
debug.logger('__generateRequestOrResponseMsg: use empty USM data')
 
-        # noinspection PyUnboundLocalVariable
-        debug.logger & debug.flagSM and debug.logger(
-            '__generateRequestOrResponseMsg: local usmUserName %r 
usmUserSecurityName %r usmUserAuthProtocol %s usmUserPrivProtocol %s 
securityEngineID %r securityName %r' % (
-                usmUserName, usmUserSecurityName, usmUserAuthProtocol, 
usmUserPrivProtocol, securityEngineID, securityName))
-
-        msg = globalData
+            debug.logger & debug.flagSM and debug.logger(
+                '__generateRequestOrResponseMsg: using blank USM info for peer 
'
+                'SNMP engine ID discovery '
+                'usmUserName "%s" '
+                'usmUserSecurityName "%s" '
+                'usmUserAuthProtocol "%s" '
+                'usmUserAuthKeyLocalized "%s" '
+                'usmUserPrivProtocol "%s" '
+                'usmUserPrivKeyLocalized "%s" for '
+                'securityEngineID "%s" and  securityName "%s"' % (
+                    usmUserName, usmUserSecurityName,
+                    usmUserAuthProtocol, usmUserAuthKeyLocalized,
+                    usmUserPrivProtocol, usmUserPrivKeyLocalized,
+                    securityEngineID and securityEngineID.prettyPrint(),
+                    securityName))
 
         # 3.1.2
         if securityLevel == 3:
@@ -648,28 +760,44 @@
                     snmpEngine.msgAndPduDsp.mibInstrumController,
                     msgAuthoritativeEngineId, msgUserName
                 )
-                debug.logger & debug.flagSM and 
debug.logger('processIncomingMsg: read user info from LCD')
+                debug.logger & debug.flagSM and debug.logger(
+                    'processIncomingMsg: read user info from LCD')
 
             except NoSuchInstanceError:
-                debug.logger & debug.flagSM and debug.logger(
-                    'processIncomingMsg: unknown securityEngineID %r 
msgUserName %r' % (
-                        msgAuthoritativeEngineId, msgUserName))
+                try:
+                    (usmUserName,
+                     usmUserSecurityName,
+                     usmUserAuthProtocol,
+                     usmUserAuthKeyLocalized,
+                     usmUserPrivProtocol,
+                     usmUserPrivKeyLocalized) = self.__getUserInfo(
+                        snmpEngine.msgAndPduDsp.mibInstrumController,
+                        self.wildcardSecurityEngineId, msgUserName
+                    )
+                    debug.logger & debug.flagSM and debug.logger(
+                        'processIncomingMsg: read wildcard user info from LCD')
 
-                usmStatsUnknownUserNames, = mibBuilder.importSymbols(
-                    '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames')
-                usmStatsUnknownUserNames.syntax += 1
+                except NoSuchInstanceError:
 
-                raise error.StatusInformation(
-                    errorIndication=errind.unknownSecurityName,
-                    oid=usmStatsUnknownUserNames.name,
-                    val=usmStatsUnknownUserNames.syntax,
-                    securityStateReference=securityStateReference,
-                    securityLevel=securityLevel,
-                    contextEngineId=contextEngineId,
-                    contextName=contextName,
-                    msgUserName=msgUserName,
-                    maxSizeResponseScopedPDU=maxSizeResponseScopedPDU
-                )
+                    debug.logger & debug.flagSM and debug.logger(
+                        'processIncomingMsg: unknown securityEngineID %r 
msgUserName %r' % (
+                            msgAuthoritativeEngineId, msgUserName))
+
+                    usmStatsUnknownUserNames, = mibBuilder.importSymbols(
+                        '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames')
+                    usmStatsUnknownUserNames.syntax += 1
+
+                    raise error.StatusInformation(
+                        errorIndication=errind.unknownSecurityName,
+                        oid=usmStatsUnknownUserNames.name,
+                        val=usmStatsUnknownUserNames.syntax,
+                        securityStateReference=securityStateReference,
+                        securityLevel=securityLevel,
+                        contextEngineId=contextEngineId,
+                        contextName=contextName,
+                        msgUserName=msgUserName,
+                        maxSizeResponseScopedPDU=maxSizeResponseScopedPDU
+                    )
 
             except PyAsn1Error:
                 debug.logger & debug.flagSM and 
debug.logger('processIncomingMsg: %s' % (sys.exc_info()[1],))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysnmp-4.4.10/pysnmp/smi/mibs/PYSNMP-USM-MIB.py 
new/pysnmp-4.4.11/pysnmp/smi/mibs/PYSNMP-USM-MIB.py
--- old/pysnmp-4.4.10/pysnmp/smi/mibs/PYSNMP-USM-MIB.py 2019-07-30 
20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/pysnmp/smi/mibs/PYSNMP-USM-MIB.py 2019-08-11 
10:12:23.000000000 +0200
@@ -34,6 +34,9 @@
 pysnmpUsmDiscovery = MibScalar((1, 3, 6, 1, 4, 1, 20408, 3, 1, 1, 1, 1, 2), 
Integer32().subtype(subtypeSpec=ConstraintsUnion(SingleValueConstraint(0, 
1))).clone(namedValues=NamedValues(("doNotDiscover", 0), ("doDiscover", 
1))).clone('doDiscover')).setMaxAccess("readwrite")
 if mibBuilder.loadTexts: pysnmpUsmDiscovery.setStatus('current')
 if mibBuilder.loadTexts: pysnmpUsmDiscovery.setDescription('Whether SNMP 
engine would try to figure out the EngineIDs of its peers by sending discover 
requests.')
+pysnmpUsmKeyType = MibScalar((1, 3, 6, 1, 4, 1, 20408, 3, 1, 1, 1, 1, 3), 
Integer32().subtype(subtypeSpec=ConstraintsUnion(SingleValueConstraint(0, 1, 
2))).clone(namedValues=NamedValues(("passphrase", 0), ("master", 1), 
("localized", 2))).clone('passphrase')).setMaxAccess("not-accessible")
+if mibBuilder.loadTexts: pysnmpUsmKeyType.setStatus('current')
+if mibBuilder.loadTexts: pysnmpUsmKeyType.setDescription('When configuring USM 
user, the value of this enumeration determines how the keys should be treated. 
The default value "passphrase" means that given keys are plain-text 
pass-phrases, "master" indicates that the keys are pre-hashed pass-phrases, 
while "localized" stands for pre-hashed pass-phrases mixed with SNMP Security 
Engine ID value.')
 pysnmpUsmUser = MibIdentifier((1, 3, 6, 1, 4, 1, 20408, 3, 1, 1, 1, 3))
 pysnmpUsmSecretTable = MibTable((1, 3, 6, 1, 4, 1, 20408, 3, 1, 1, 1, 2), )
 if mibBuilder.loadTexts: pysnmpUsmSecretTable.setStatus('current')
@@ -75,4 +78,4 @@
 if mibBuilder.loadTexts: pysnmpUsmKeyPriv.setDescription("User's non-localized 
key used for encryption.")
 pysnmpUsmMIBCompliances = MibIdentifier((1, 3, 6, 1, 4, 1, 20408, 3, 1, 1, 2, 
1))
 pysnmpUsmMIBGroups = MibIdentifier((1, 3, 6, 1, 4, 1, 20408, 3, 1, 1, 2, 2))
-mibBuilder.exportSymbols("PYSNMP-USM-MIB", pysnmpUsmCfg=pysnmpUsmCfg, 
pysnmpUsmDiscoverable=pysnmpUsmDiscoverable, 
pysnmpUsmKeyEntry=pysnmpUsmKeyEntry, pysnmpUsmKeyTable=pysnmpUsmKeyTable, 
pysnmpUsmKeyPrivLocalized=pysnmpUsmKeyPrivLocalized, 
pysnmpUsmMIBCompliances=pysnmpUsmMIBCompliances, 
pysnmpUsmMIBObjects=pysnmpUsmMIBObjects, 
pysnmpUsmSecretTable=pysnmpUsmSecretTable, PYSNMP_MODULE_ID=pysnmpUsmMIB, 
pysnmpUsmSecretEntry=pysnmpUsmSecretEntry, 
pysnmpUsmMIBConformance=pysnmpUsmMIBConformance, pysnmpUsmUser=pysnmpUsmUser, 
pysnmpUsmKeyAuth=pysnmpUsmKeyAuth, 
pysnmpUsmSecretPrivKey=pysnmpUsmSecretPrivKey, 
pysnmpUsmKeyAuthLocalized=pysnmpUsmKeyAuthLocalized, pysnmpUsmMIB=pysnmpUsmMIB, 
pysnmpUsmDiscovery=pysnmpUsmDiscovery, 
pysnmpUsmSecretUserName=pysnmpUsmSecretUserName, 
pysnmpUsmKeyPriv=pysnmpUsmKeyPriv, 
pysnmpUsmSecretAuthKey=pysnmpUsmSecretAuthKey, 
pysnmpUsmSecretStatus=pysnmpUsmSecretStatus, 
pysnmpUsmMIBGroups=pysnmpUsmMIBGroups)
+mibBuilder.exportSymbols("PYSNMP-USM-MIB", pysnmpUsmCfg=pysnmpUsmCfg, 
pysnmpUsmDiscoverable=pysnmpUsmDiscoverable, pysnmpUsmKeyType=pysnmpUsmKeyType, 
pysnmpUsmKeyEntry=pysnmpUsmKeyEntry, pysnmpUsmKeyTable=pysnmpUsmKeyTable, 
pysnmpUsmKeyPrivLocalized=pysnmpUsmKeyPrivLocalized, 
pysnmpUsmMIBCompliances=pysnmpUsmMIBCompliances, 
pysnmpUsmMIBObjects=pysnmpUsmMIBObjects, 
pysnmpUsmSecretTable=pysnmpUsmSecretTable, PYSNMP_MODULE_ID=pysnmpUsmMIB, 
pysnmpUsmSecretEntry=pysnmpUsmSecretEntry, 
pysnmpUsmMIBConformance=pysnmpUsmMIBConformance, pysnmpUsmUser=pysnmpUsmUser, 
pysnmpUsmKeyAuth=pysnmpUsmKeyAuth, 
pysnmpUsmSecretPrivKey=pysnmpUsmSecretPrivKey, 
pysnmpUsmKeyAuthLocalized=pysnmpUsmKeyAuthLocalized, pysnmpUsmMIB=pysnmpUsmMIB, 
pysnmpUsmDiscovery=pysnmpUsmDiscovery, 
pysnmpUsmSecretUserName=pysnmpUsmSecretUserName, 
pysnmpUsmKeyPriv=pysnmpUsmKeyPriv, 
pysnmpUsmSecretAuthKey=pysnmpUsmSecretAuthKey, 
pysnmpUsmSecretStatus=pysnmpUsmSecretStatus, 
pysnmpUsmMIBGroups=pysnmpUsmMIBGroups)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pysnmp-4.4.10/pysnmp/smi/mibs/instances/__PYSNMP-USM-MIB.py 
new/pysnmp-4.4.11/pysnmp/smi/mibs/instances/__PYSNMP-USM-MIB.py
--- old/pysnmp-4.4.10/pysnmp/smi/mibs/instances/__PYSNMP-USM-MIB.py     
2019-07-30 20:29:22.000000000 +0200
+++ new/pysnmp-4.4.11/pysnmp/smi/mibs/instances/__PYSNMP-USM-MIB.py     
2019-08-11 10:12:23.000000000 +0200
@@ -7,17 +7,21 @@
 MibScalarInstance, = mibBuilder.importSymbols('SNMPv2-SMI', 
'MibScalarInstance')
 
 (pysnmpUsmDiscoverable,
- pysnmpUsmDiscovery) = mibBuilder.importSymbols(
+ pysnmpUsmDiscovery,
+ pysnmpUsmKeyType) = mibBuilder.importSymbols(
     'PYSNMP-USM-MIB',
     'pysnmpUsmDiscoverable',
-    'pysnmpUsmDiscovery'
+    'pysnmpUsmDiscovery',
+    'pysnmpUsmKeyType'
 )
 
 __pysnmpUsmDiscoverable = MibScalarInstance(pysnmpUsmDiscoverable.name, (0,), 
pysnmpUsmDiscoverable.syntax)
 __pysnmpUsmDiscovery = MibScalarInstance(pysnmpUsmDiscovery.name, (0,), 
pysnmpUsmDiscovery.syntax)
+__pysnmpUsmKeyType = MibScalarInstance(pysnmpUsmKeyType.name, (0,), 
pysnmpUsmKeyType.syntax)
 
 mibBuilder.exportSymbols(
     "__PYSNMP-USM-MIB",
     pysnmpUsmDiscoverable=__pysnmpUsmDiscoverable,
-    pysnmpUsmDiscovery=__pysnmpUsmDiscovery
+    pysnmpUsmDiscovery=__pysnmpUsmDiscovery,
+    pysnmpUsmKeyType=__pysnmpUsmKeyType
 )


Reply via email to