From 65e92864a32600019a24e61594c4f996c1f2d411 Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Sat, 3 Aug 2019 13:40:49 +0200 Subject: Add USM master and localized keys configuration support (#295) Added new optional parameters to `addUsmUser()` and `hlapi.UsmUserData()` functions allowing specifying key material type being passed to the respective routines. Plain-text pass-phrase remains the default, while user can change that to `master` or `localized` types. Refer to RFC3414 for technical details on SNMP USM key localization algorithm. --- pysnmp/hlapi/__init__.py | 2 +- pysnmp/hlapi/v3arch/__init__.py | 9 +++ pysnmp/hlapi/v3arch/auth.py | 145 ++++++++++++++++++++++++++++++++-------- pysnmp/hlapi/v3arch/lcd.py | 6 +- 4 files changed, 131 insertions(+), 31 deletions(-) (limited to 'pysnmp/hlapi') diff --git a/pysnmp/hlapi/__init__.py b/pysnmp/hlapi/__init__.py index 6da0e1cd..31aef89a 100644 --- a/pysnmp/hlapi/__init__.py +++ b/pysnmp/hlapi/__init__.py @@ -5,5 +5,5 @@ # License: http://snmplabs.com/pysnmp/license.html # -# default is synchronous asyncore-based API +# default is v3arch from pysnmp.hlapi.v3arch import * diff --git a/pysnmp/hlapi/v3arch/__init__.py b/pysnmp/hlapi/v3arch/__init__.py index 565df668..901c488e 100644 --- a/pysnmp/hlapi/v3arch/__init__.py +++ b/pysnmp/hlapi/v3arch/__init__.py @@ -60,3 +60,12 @@ usmAesBlumenthalCfb192Protocol = auth.usmAesBlumenthalCfb192Protocol usmAesBlumenthalCfb256Protocol = auth.usmAesBlumenthalCfb256Protocol """The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 `_)""" + +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 --git a/pysnmp/hlapi/v3arch/auth.py b/pysnmp/hlapi/v3arch/auth.py index 18b4b328..16363546 100644 --- a/pysnmp/hlapi/v3arch/auth.py +++ b/pysnmp/hlapi/v3arch/auth.py @@ -18,7 +18,8 @@ __all__ = [ 'USM_PRIV_CBC56_DES', 'USM_PRIV_CBC168_3DES', 'USM_PRIV_CFB128_AES', 'USM_PRIV_CFB192_AES', 'USM_PRIV_CFB256_AES', 'USM_PRIV_CFB192_AES_BLUMENTHAL', - 'USM_PRIV_CFB256_AES_BLUMENTHAL', + 'USM_PRIV_CFB256_AES_BLUMENTHAL', 'USM_KEY_TYPE_PASSPHRASE', + 'USM_KEY_TYPE_MASTER', 'USM_KEY_TYPE_LOCALIZED', # backward-compatible constants 'usm3DESEDEPrivProtocol', 'usmAesCfb128Protocol', 'usmAesCfb192Protocol', 'usmAesCfb256Protocol', @@ -27,7 +28,8 @@ __all__ = [ 'usmHMACSHAAuthProtocol', 'usmHMAC128SHA224AuthProtocol', 'usmHMAC192SHA256AuthProtocol', 'usmHMAC256SHA384AuthProtocol', 'usmHMAC384SHA512AuthProtocol', 'usmNoAuthProtocol', - 'usmNoPrivProtocol' + 'usmNoPrivProtocol', 'usmKeyTypePassphrase', 'usmKeyTypeMaster', + 'usmKeyTypeLocalized' ] @@ -59,22 +61,41 @@ USM_PRIV_CBC56_DES = config.USM_PRIV_CBC56_DES """The CBC56-DES Symmetric Encryption Protocol (:RFC:`3414#section-8`)""" USM_PRIV_CBC168_3DES = config.USM_PRIV_CBC168_3DES -"""The 3DES-EDE Symmetric Encryption Protocol (`draft-reeder-snmpv3-usm-3desede-00 `_)""" +"""The 3DES-EDE Symmetric Encryption Protocol (`draft-reeder-snmpv3-usm-3desede-00 \ +`_)""" USM_PRIV_CFB128_AES = config.USM_PRIV_CFB128_AES """The CFB128-AES-128 Symmetric Encryption Protocol (:RFC:`3826#section-3`)""" USM_PRIV_CFB192_AES = config.USM_PRIV_CFB192_AES -"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 `_) with Reeder key localization""" +"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 \ +`_) \ +with Reeder key localization""" USM_PRIV_CFB256_AES = config.USM_PRIV_CFB256_AES -"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 `_) with Reeder key localization""" +"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 \ +`_) \ +with Reeder key localization""" USM_PRIV_CFB192_AES_BLUMENTHAL = config.USM_PRIV_CFB192_AES_BLUMENTHAL -"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 `_)""" +"""The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 \ +`_)""" USM_PRIV_CFB256_AES_BLUMENTHAL = config.USM_PRIV_CFB256_AES_BLUMENTHAL -"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 `_)""" +"""The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 \ +`_)""" + +# USM key types (PYSNMP-USM-MIB::pysnmpUsmKeyType) + +USM_KEY_TYPE_PASSPHRASE = config.USM_KEY_TYPE_PASSPHRASE +"""USM key material type - plain-text pass phrase (:RFC:`3414#section-2.6`)""" + +USM_KEY_TYPE_MASTER = config.USM_KEY_TYPE_MASTER +"""USM key material type - hashed pass-phrase AKA master key (:RFC:`3414#section-2.6`)""" + +USM_KEY_TYPE_LOCALIZED = config.USM_KEY_TYPE_LOCALIZED +"""USM key material type - hashed pass-phrase hashed with Context SNMP Engine ID \ +(:RFC:`3414#section-2.6`)""" # Backward-compatible protocol IDs usmNoAuthProtocol = USM_AUTH_NONE @@ -93,6 +114,10 @@ usmAesCfb256Protocol = USM_PRIV_CFB256_AES usmAesBlumenthalCfb192Protocol = USM_PRIV_CFB192_AES_BLUMENTHAL usmAesBlumenthalCfb256Protocol = USM_PRIV_CFB256_AES_BLUMENTHAL +usmKeyTypePassphrase = USM_KEY_TYPE_PASSPHRASE +usmKeyTypeMaster = USM_KEY_TYPE_MASTER +usmKeyTypeLocalized = USM_KEY_TYPE_LOCALIZED + class CommunityData(object): """Creates SNMP v1/v2c configuration entry. @@ -109,21 +134,30 @@ class CommunityData(object): 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 @@ -253,21 +287,26 @@ class UsmUserData(object): 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. @@ -281,7 +320,23 @@ class UsmUserData(object): * :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. + + 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. @@ -294,6 +349,29 @@ class UsmUserData(object): * :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` + + Examples -------- >>> from pysnmp.hlapi import UsmUserData @@ -316,8 +394,9 @@ class UsmUserData(object): authKey=None, privKey=None, authProtocol=None, privProtocol=None, securityEngineId=None, - securityName=None): - + securityName=None, + authKeyType=USM_KEY_TYPE_PASSPHRASE, + privKeyType=USM_KEY_TYPE_PASSPHRASE): self.userName = userName if securityName is None: @@ -353,6 +432,8 @@ class UsmUserData(object): self.privProtocol = privProtocol self.securityEngineId = securityEngineId + self.authKeyType = authKeyType + self.privKeyType = privKeyType def __hash__(self): raise TypeError('%s is not hashable' % self.__class__.__name__) @@ -360,17 +441,22 @@ class UsmUserData(object): def __repr__(self): return ('%s(userName=%r, authKey=, privKey=, ' 'authProtocol=%r, privProtocol=%r, securityEngineId=%r, ' - 'securityName=%r)') % ( - self.__class__.__name__, self.userName, - self.authProtocol, self.privProtocol, + 'securityName=%r, authKeyType=%r, privKeyType=%r)') % ( + self.__class__.__name__, + self.userName, + self.authProtocol, + self.privProtocol, self.securityEngineId is None and '' 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, @@ -378,4 +464,7 @@ class UsmUserData(object): 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 USM_KEY_TYPE_PASSPHRASE, + privKeyType is None and self.privKeyType or USM_KEY_TYPE_PASSPHRASE + ) diff --git a/pysnmp/hlapi/v3arch/lcd.py b/pysnmp/hlapi/v3arch/lcd.py index 0e1eb9c5..f01f6107 100644 --- a/pysnmp/hlapi/v3arch/lcd.py +++ b/pysnmp/hlapi/v3arch/lcd.py @@ -67,8 +67,10 @@ class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): 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 -- cgit v1.2.1