SNMP-USER-BASED-SM-MIB(7)

πŸ“¦
version 25.3.2.8 Β· 3 versions
, in debian bookworm, ubuntu jammy, ubuntu noble

🌸 SNMP-USER-BASED-SM-MIB(7) 🌸

okay bestie, this is the SNMP-USER-BASED-SM-MIB(7) manual page from section MIB β€” and it's literally the Erlang/OTP MIB module for the SNMP user-based security model. We're in part 1 of 4, so no signing off, just vibes and exact MIB source. πŸ’…

✨ NAME ✨

SNMP-USER-BASED-SM-MIB - The Erlang/OTP MIB module for the SNMP user-based security model.

πŸ¦‹ DESCRIPTION πŸ¦‹

bestie, the whole section is a MIB module definition, so the code blocks are sacred β€” I'm keeping the source exact and adding commentary around it. First up, the module opens and pulls in its imports:

SNMP-USER-BASED-SM-MIB DEFINITIONS ::= BEGIN

IMPORTS
    MODULE-IDENTITY, OBJECT-TYPE,
    OBJECT-IDENTITY,
    snmpModules, Counter32                FROM SNMPv2-SMI
    TEXTUAL-CONVENTION, TestAndIncr,
    RowStatus, RowPointer,
    StorageType, AutonomousType           FROM SNMPv2-TC
    MODULE-COMPLIANCE, OBJECT-GROUP       FROM SNMPv2-CONF
    SnmpAdminString, SnmpEngineID,
    snmpAuthProtocols, snmpPrivProtocols  FROM SNMP-FRAMEWORK-MIB;

Then comes the snmpUsmMIB MODULE-IDENTITY block, and it's giving very official main-character energy. It has the timestamp, the org, the whole contact-info cast, the description, and the revision history:

snmpUsmMIB MODULE-IDENTITY
    LAST-UPDATED "9901200000Z"            -- 20 Jan 1999, midnight
    ORGANIZATION "SNMPv3 Working Group"
    CONTACT-INFO "WG-email:   snmpv3@tis.com
                  Subscribe:  majordomo@tis.com
                              In msg body:  subscribe snmpv3

                  Chair:      Russ Mundy
                              Trusted Information Systems
                  postal:     3060 Washington Rd
                              Glenwood MD 21738
                              USA
                  email:      mundy@tis.com
                  phone:      +1-301-854-6889

                  Co-editor   Uri Blumenthal
                              IBM T. J. Watson Research
                  postal:     30 Saw Mill River Pkwy,
                              Hawthorne, NY 10532
                              USA
                  email:      uri@watson.ibm.com
                  phone:      +1-914-784-7964

                  Co-editor:  Bert Wijnen
                              IBM T. J. Watson Research
                  postal:     Schagen 33
                              3461 GL Linschoten
                              Netherlands
                  email:      wijnen@vnet.ibm.com
                  phone:      +31-348-432-794
                 "
    DESCRIPTION  "The management information definitions for the
                  SNMP User-based Security Model.
                 "
--  Revision history
    REVISION     "9901200000Z"            -- 20 Jan 1999, midnight
                                          -- RFC-Editor assigns RFCxxxx
    DESCRIPTION  "Clarifications, published as RFCxxxx"

    REVISION     "9711200000Z"            -- 20 Nov 1997, midnight
    DESCRIPTION  "Initial version, published as RFC2274"

    ::= { snmpModules 15 }

Next are the administrative assignments and the authentication/privacy protocol identities. iykyk, this is where the MIB says which protocol objects live where:

-- Administrative assignments ****************************************

usmMIBObjects     OBJECT IDENTIFIER ::= { snmpUsmMIB 1 }
usmMIBConformance OBJECT IDENTIFIER ::= { snmpUsmMIB 2 }

-- Identification of Authentication and Privacy Protocols ************

usmNoAuthProtocol OBJECT-IDENTITY
    STATUS        current
    DESCRIPTION  "No Authentication Protocol."
    ::= { snmpAuthProtocols 1 }

usmHMACMD5AuthProtocol OBJECT-IDENTITY
    STATUS        current
    DESCRIPTION  "The HMAC-MD5-96 Digest Authentication Protocol."
    REFERENCE    "- H. Krawczyk, M. Bellare, R. Canetti HMAC:
                    Keyed-Hashing for Message Authentication,
                    RFC2104, Feb 1997.
                  - Rivest, R., Message Digest Algorithm MD5, RFC1321.
                 "
    ::= { snmpAuthProtocols 2 }

usmHMACSHAAuthProtocol OBJECT-IDENTITY
    STATUS        current
    DESCRIPTION  "The HMAC-SHA-96 Digest Authentication Protocol."
    REFERENCE    "- H. Krawczyk, M. Bellare, R. Canetti, HMAC:
                    Keyed-Hashing for Message Authentication,
                    RFC2104, Feb 1997.
                  - Secure Hash Algorithm. NIST FIPS 180-1.
                 "
    ::= { snmpAuthProtocols 3 }

usmNoPrivProtocol OBJECT-IDENTITY
    STATUS        current
    DESCRIPTION  "No Privacy Protocol."
    ::= { snmpPrivProtocols 1 }

usmDESPrivProtocol OBJECT-IDENTITY
    STATUS        current
    DESCRIPTION  "The CBC-DES Symmetric Encryption Protocol."
    REFERENCE    "- Data Encryption Standard, National Institute of
                    Standards and Technology.  Federal Information
                    Processing Standard (FIPS) Publication 46-1.
                    Supersedes FIPS Publication 46,
                    (January, 1977; reaffirmed January, 1988).

                  - Data Encryption Algorithm, American National
                    Standards Institute.  ANSI X3.92-1981,
                    (December, 1980).

                  - DES Modes of Operation, National Institute of
                    Standards and Technology.  Federal Information
                    Processing Standard (FIPS) Publication 81,
                    (December, 1980).

                  - Data Encryption Algorithm - Modes of Operation,
                    American National Standards Institute.
                    ANSI X3.106-1983, (May 1983).
                 "
    ::= { snmpPrivProtocols 2 }

And now the big one: the KeyChange textual convention. Part 1 ends right as it's about to show the MD5 example, so hold that thought. No spoilers, bestie. πŸ’–

-- Textual Conventions ***********************************************

KeyChange ::=     TEXTUAL-CONVENTION
   STATUS         current
   DESCRIPTION
         "Every definition of an object with this syntax must identify
          a protocol P, a secret key K, and a hash algorithm H
          that produces output of L octets.

          The object's value is a manager-generated, partially-random
          value which, when modified, causes the value of the secret
          key K, to be modified via a one-way function.

          The value of an instance of this object is the concatenation
          of two components: first a 'random' component and then a
          'delta' component.

          The lengths of the random and delta components
          are given by the corresponding value of the protocol P;
          if P requires K to be a fixed length, the length of both the
          random and delta components is that fixed length; if P
          allows the length of K to be variable up to a particular
          maximum length, the length of the random component is that
          maximum length and the length of the delta component is any
          length less than or equal to that maximum length.
          For example, usmHMACMD5AuthProtocol requires K to be a fixed
          length of 16 octets and L - of 16 octets.
          usmHMACSHAAuthProtocol requires K to be a fixed length of
          20 octets and L - of 20 octets. Other protocols may define
          other sizes, as deemed appropriate.

          When a requester wants to change the old key K to a new
          key keyNew on a remote entity, the 'random' component is
          obtained from either a true random generator, or from a
          pseudorandom generator, and the 'delta' component is
          computed as follows:

           - a temporary variable is initialized to the existing value
             of K;
           - if the length of the keyNew is greater than L octets,
             then:
              - the random component is appended to the value of the
                temporary variable, and the result is input to the
                the hash algorithm H to produce a digest value, and
                the temporary variable is set to this digest value;
              - the value of the temporary variable is XOR-ed with
                the first (next) L-octets (16 octets in case of MD5)
                of the keyNew to produce the first (next) L-octets
                (16 octets in case of MD5) of the 'delta' component.
              - the above two steps are repeated until the unused
                portion of the keyNew component is L octets or less,
           - the random component is appended to the value of the
             temporary variable, and the result is input to the
             hash algorithm H to produce a digest value;
           - this digest value, truncated if necessary to be the same
             length as the unused portion of the keyNew, is XOR-ed
             with the unused portion of the keyNew to produce the
             (final portion of the) 'delta' component.

           For example, using MD5 as the hash algorithm H:

              iterations = (lenOfDelta - 1)/16; /* integer division */
              temp = keyOld;
              for (i = 0; i < iterations; i++) {
                  temp = MD5 (temp || random);
                  delta[i*16 .. (i*16)+15] =
                         temp XOR keyNew[i*16 .. (i*16)+15];
              }
              temp = MD5 (temp || random);
              delta[i*16 .. lenOfDelta-1] =
                     temp XOR keyNew[i*16 .. lenOfDelta-1];

          The 'random' and 'delta' components are then concatenated as
          described above, and the resulting octet string is sent to
          the recipient as the new value of an instance of this object.

          At the receiver side, when an instance of this object is set
          to a new value, then a new value of K is computed as follows:

           - a temporary variable is initialized to the existing value
             of K;
           - if the length of the delta component is greater than L
             octets, then:
              - the random component is appended to the value of the
                temporary variable, and the result is input to the
                hash algorithm H to produce a digest value, and the
                temporary variable is set to this digest value;
              - the value of the temporary variable is XOR-ed with
                the first (next) L-octets (16 octets in case of MD5)
                of the delta component to produce the first (next)
                L-octets (16 octets in case of MD5) of the new value
                of K.
              - the above two steps are repeated until the unused
                portion of the delta component is L octets or less,
           - the random component is appended to the value of the
             temporary variable, and the result is input to the
             hash algorithm H to produce a digest value;
           - this digest value, truncated if necessary to be the same
             length as the unused portion of the delta component, is
             XOR-ed with the unused portion of the delta component to
             produce the (final portion of the) new value of K.

           For example, using MD5 as the hash algorithm H:

okay so picking up mid-KeyChange β€” here's the exact pseudocode loop, and it's giving "hash then XOR" realness:

                     iterations = (lenOfDelta - 1)/16; /* integer division */
                     temp = keyOld;
                     for (i = 0; i < iterations; i++) {
                         temp = MD5 (temp || random);
                         keyNew[i*16 .. (i*16)+15] =
                                temp XOR delta[i*16 .. (i*16)+15];
                     }
                     temp = MD5 (temp || random);
                     keyNew[i*16 .. lenOfDelta-1] =
                            temp XOR delta[i*16 .. lenOfDelta-1];

The next bits are part of the same DESCRIPTION, so keep them close:

                 The value of an object with this syntax, whenever it is
                 retrieved by the management protocol, is always the zero
                 length string.

                 Note that the keyOld and keyNew are the localized keys.

                 Note that it is probably wise that when an SNMP entity sends
                 a SetRequest to change a key, that it keeps a copy of the old
                 key until it has confirmed that the key change actually
                 succeeded.
                "
           SYNTAX       OCTET STRING

Translation, bestie: whenever the management protocol retrieves an object with this syntax, the value is always the zero-length string. keyOld and keyNew are the localized keys. And that "probably wise" note is literally saying: if an SNMP entity sends a SetRequest to change a key, it should keep a copy of the old key until it has confirmed the key change actually succeeded. Don't skip that part, it's important. πŸ’…


Next up: the stats block. These counters are the "why did you drop my packet" receipts. All of them are Counter32, read-only, current. Here's the exact MIB, no cap:

       -- Statistics for the User-based Security Model **********************

       usmStats         OBJECT IDENTIFIER ::= { usmMIBObjects 1 }

       usmStatsUnsupportedSecLevels OBJECT-TYPE
           SYNTAX       Counter32
           MAX-ACCESS   read-only
           STATUS       current
           DESCRIPTION "The total number of packets received by the SNMP
                        engine which were dropped because they requested a
                        securityLevel that was unknown to the SNMP engine
                        or otherwise unavailable.
                       "
           ::= { usmStats 1 }

       usmStatsNotInTimeWindows OBJECT-TYPE
           SYNTAX       Counter32
           MAX-ACCESS   read-only
           STATUS       current
           DESCRIPTION "The total number of packets received by the SNMP
                        engine which were dropped because they appeared
                        outside of the authoritative SNMP engine's window.
                       "
           ::= { usmStats 2 }

       usmStatsUnknownUserNames OBJECT-TYPE
           SYNTAX       Counter32
           MAX-ACCESS   read-only
           STATUS       current
           DESCRIPTION "The total number of packets received by the SNMP
                        engine which were dropped because they referenced a
                        user that was not known to the SNMP engine.
                       "
           ::= { usmStats 3 }

       usmStatsUnknownEngineIDs OBJECT-TYPE
           SYNTAX       Counter32
           MAX-ACCESS   read-only
           STATUS       current
           DESCRIPTION "The total number of packets received by the SNMP
                        engine which were dropped because they referenced an
                        snmpEngineID that was not known to the SNMP engine.
                       "
           ::= { usmStats 4 }

       usmStatsWrongDigests OBJECT-TYPE
           SYNTAX       Counter32
           MAX-ACCESS   read-only
           STATUS       current
           DESCRIPTION "The total number of packets received by the SNMP
                        engine which were dropped because they didn't
                        contain the expected digest value.
                       "
           ::= { usmStats 5 }

       usmStatsDecryptionErrors OBJECT-TYPE
           SYNTAX       Counter32
           MAX-ACCESS   read-only
           STATUS       current
           DESCRIPTION "The total number of packets received by the SNMP
                        engine which were dropped because they could not be
                        decrypted.
                       "
           ::= { usmStats 6 }

So the six little icons of pain are:

  • usmStatsUnsupportedSecLevels β€” requested a securityLevel that was unknown or unavailable.
  • usmStatsNotInTimeWindows β€” appeared outside the authoritative SNMP engine's window.
  • usmStatsUnknownUserNames β€” referenced a user the engine didn't know.
  • usmStatsUnknownEngineIDs β€” referenced an unknown snmpEngineID.
  • usmStatsWrongDigests β€” didn't have the expected digest value.
  • usmStatsDecryptionErrors β€” couldn't be decrypted.

All Counter32, all read-only, all current. Look, don't touch. 🫢


Now the usmUser group. First up:

       -- The usmUser Group ************************************************

       usmUser          OBJECT IDENTIFIER ::= { usmMIBObjects 2 }

       usmUserSpinLock  OBJECT-TYPE
           SYNTAX       TestAndIncr
           MAX-ACCESS   read-write
           STATUS       current
           DESCRIPTION "An advisory lock used to allow several cooperating
                        Command Generator Applications to coordinate their
                        use of facilities to alter secrets in the
                        usmUserTable.
                       "
           ::= { usmUser 1 }

usmUserSpinLock is a TestAndIncr, read-write advisory lock. Its whole job is letting several cooperating Command Generator Applications coordinate when they're altering secrets in usmUserTable. It's the group-chat "who's typing" but for secret changes. ✨


Now the big one: usmUserTable. It's SEQUENCE OF UsmUserEntry, not-accessible, and the DESCRIPTION has a whole 13-step procedure. I'm putting the exact block below because you need every step, including the usmUserPulic typo β€” do not fix it, it's in the MIB. πŸ™ˆ

       -- The table of valid users for the User-based Security Model ********

       usmUserTable     OBJECT-TYPE
           SYNTAX       SEQUENCE OF UsmUserEntry
           MAX-ACCESS   not-accessible
           STATUS       current
           DESCRIPTION "The table of users configured in the SNMP engine's
                        Local Configuration Datastore (LCD).

                        To create a new user (i.e., to instantiate a new
                        conceptual row in this table), it is recommended to
                        follow this procedure:

                          1)  GET(usmUserSpinLock.0) and save in sValue.
                          2)  SET(usmUserSpinLock.0=sValue,
                                  usmUserCloneFrom=templateUser,
                                  usmUserStatus=createAndWait)
                              You should use a template user to clone from
                              which has the proper auth/priv protocol defined.

                        If the new user is to use privacy:

                          3)  generate the keyChange value based on the secret
                              privKey of the clone-from user and the secret key
                              to be used for the new user. Let us call this
                              pkcValue.
                          4)  GET(usmUserSpinLock.0) and save in sValue.
                          5)  SET(usmUserSpinLock.0=sValue,
                                  usmUserPrivKeyChange=pkcValue
                                  usmUserPublic=randomValue1)
                          6)  GET(usmUserPulic) and check it has randomValue1.
                              If not, repeat steps 4-6.

                        If the new user will never use privacy:

                          7)  SET(usmUserPrivProtocol=usmNoPrivProtocol)

                        If the new user is to use authentication:

                          8)  generate the keyChange value based on the secret
                              authKey of the clone-from user and the secret key
                              to be used for the new user. Let us call this
                              akcValue.
                          9)  GET(usmUserSpinLock.0) and save in sValue.
                          10) SET(usmUserSpinLock.0=sValue,
                                  usmUserAuthKeyChange=akcValue
                                  usmUserPublic=randomValue2)
                          11) GET(usmUserPulic) and check it has randomValue2.
                              If not, repeat steps 9-11.

                        If the new user will never use authentication:

                          12) SET(usmUserAuthProtocol=usmNoAuthProtocol)

                        Finally, activate the new user:

                          13) SET(usmUserStatus=active)

                        The new user should now be available and ready to be
                        used for SNMPv3 communication. Note however that access
                        to MIB data must be provided via configuration of the
                        SNMP-VIEW-BASED-ACM-MIB.

                        The use of usmUserSpinlock is to avoid conflicts with
                        another SNMP command responder application which may
                        also be acting on the usmUserTable.
                       "
           ::= { usmUser 2 }

The vibe of the procedure: get the spinlock into sValue, SET the spinlock plus usmUserCloneFrom=templateUser and usmUserStatus=createAndWait, then handle privacy key change with usmUserPrivKeyChange and usmUserPublic=randomValue1 (check via usmUserPulic, repeat 4-6 if needed), set usmNoPrivProtocol if privacy is never used, do the auth version with usmUserAuthKeyChange and usmUserPublic=randomValue2 (check via usmUserPulic, repeat 9-11 if needed), set usmNoAuthProtocol if auth is never used, and finally usmUserStatus=active. Also: access to MIB data still has to come from configuring SNMP-VIEW-BASED-ACM-MIB. The spinlock exists to avoid conflicts with another SNMP command responder application that may also be acting on usmUserTable. πŸ”₯


Next:

       usmUserEntry     OBJECT-TYPE
           SYNTAX       UsmUserEntry
           MAX-ACCESS   not-accessible
           STATUS       current
           DESCRIPTION "A user configured in the SNMP engine's Local
                        Configuration Datastore (LCD) for the User-based
                        Security Model.
                       "
           INDEX       { usmUserEngineID,
                         usmUserName
                       }
           ::= { usmUserTable 1 }

usmUserEntry is not-accessible, indexed by usmUserEngineID and usmUserName, and it lives at { usmUserTable 1 }. It's one user configured in the SNMP engine's Local Configuration Datastore (LCD) for the User-based Security Model. Iconic. πŸ‘‘

Here's the full UsmUserEntry SEQUENCE, every field, no skips:

       UsmUserEntry ::= SEQUENCE
           {
               usmUserEngineID         SnmpEngineID,
               usmUserName             SnmpAdminString,
               usmUserSecurityName     SnmpAdminString,
               usmUserCloneFrom        RowPointer,
               usmUserAuthProtocol     AutonomousType,
               usmUserAuthKeyChange    KeyChange,
               usmUserOwnAuthKeyChange KeyChange,
               usmUserPrivProtocol     AutonomousType,
               usmUserPrivKeyChange    KeyChange,
               usmUserOwnPrivKeyChange KeyChange,
               usmUserPublic           OCTET STRING,
               usmUserStorageType      StorageType,
               usmUserStatus           RowStatus
           }

Then the first three columns:

       usmUserEngineID  OBJECT-TYPE
           SYNTAX       SnmpEngineID
           MAX-ACCESS   not-accessible
           STATUS       current
           DESCRIPTION "An SNMP engine's administratively-unique identifier.

                        In a simple agent, this value is always that agent's
                        own snmpEngineID value.

                        The value can also take the value of the snmpEngineID
                        of a remote SNMP engine with which this user can
                        communicate.
                       "
           ::= { usmUserEntry 1 }

       usmUserName      OBJECT-TYPE
           SYNTAX       SnmpAdminString (SIZE(1..32))
           MAX-ACCESS   not-accessible
           STATUS       current
           DESCRIPTION "A human readable string representing the name of
                        the user.

                        This is the (User-based Security) Model dependent
                        security ID.
                       "
           ::= { usmUserEntry 2 }

       usmUserSecurityName OBJECT-TYPE
           SYNTAX       SnmpAdminString
           MAX-ACCESS   read-only
           STATUS       current
           DESCRIPTION "A human readable string representing the user in
                        Security Model independent format.

                        The default transformation of the User-based Security
                        Model dependent security ID to the securityName and
                        vice versa is the identity function so that the
                        securityName is the same as the userName.
                       "
           ::= { usmUserEntry 3 }

So usmUserEngineID is an SNMP engine's administratively-unique identifier. In a simple agent it's always that agent's own snmpEngineID value, but it can also be the snmpEngineID of a remote SNMP engine this user can communicate with. usmUserName is a human-readable string, SIZE(1..32), and it's the (User-based Security) Model dependent security ID. usmUserSecurityName is read-only, human-readable, and in Security Model independent format. Because the default transformation between the USM-dependent security ID and the securityName is the identity function, securityName is the same as userName. Slay. πŸ’–


And now usmUserCloneFrom. It's read-create, RowPointer to another conceptual row in usmUserTable; that other row is the clone-from user. When a new user is created, the privacy and authentication parameters β€” usmUserAuthProtocol and usmUserPrivProtocol β€” must be cloned from its clone-from user, and they're copied regardless of what the current value is. Cloning also sets the new user's initial secret authentication key (authKey) and secret encryption key (privKey) to the same values as the clone-from user's corresponding secrets. Here's the exact block β€” and this part ends mid-description, so no closing quote yet:

       usmUserCloneFrom OBJECT-TYPE
           SYNTAX       RowPointer
           MAX-ACCESS   read-create
           STATUS       current
           DESCRIPTION "A pointer to another conceptual row in this
                        usmUserTable.  The user in this other conceptual
                        row is called the clone-from user.

                        When a new user is created (i.e., a new conceptual
                        row is instantiated in this table), the privacy and
                        authentication parameters of the new user must be
                        cloned from its clone-from user. These parameters are:
                          - authentication protocol (usmUserAuthProtocol)
                          - privacy protocol (usmUserPrivProtocol)
                        They will be copied regardless of what the current
                        value is.

                        Cloning also causes the initial values of the secret
                        authentication key (authKey) and the secret encryption
                        key (privKey) of the new user to be set to the same
                        value as the corresponding secret of the clone-from
                        user.

Okay so the first time a management operation sets an instance of this object β€” whether that happens right at instantiation or later β€” the cloning process gets invoked. Any writes after that? They go through fine, but the receiver takes no action. The cloning process flops with an 'inconsistentName' error if the conceptual row representing the clone-from user doesn't exist, or if it isn't in an active state when the cloning process is invoked. When you read this object, you get the ZeroDotZero OID back. And its OID assignment is ::= { usmUserEntry 4 }. πŸ’…


πŸ¦‹ usmUserAuthProtocol

  • SYNTAX AutonomousType
  • MAX-ACCESS read-create
  • STATUS current
  • DEFVAL { usmNoAuthProtocol }
  • OID ::= { usmUserEntry 5 }

This one tells you whether messages sent on behalf of this user to/from the SNMP engine identified by usmUserEngineID can be authenticated β€” and if they can, which authentication protocol type is being used. ✨

An instance of this object gets created at the same time as any other object instance for the same user. Like, it's part of processing the set operation that creates the first object instance in the same conceptual row. No cap.

If an initial set operation β€” meaning at row creation time β€” tries to set a value for an unknown or unsupported protocol, then a 'wrongValue' error must be returned. The value gets overwritten/set when a set operation is performed on the corresponding instance of usmUserCloneFrom.

Once instantiated, the value of such an instance of this object can only be changed via a set operation to the value of usmNoAuthProtocol. If a set operation tries to change the value of an existing instance of this object to any value other than usmNoAuthProtocol, then an 'inconsistentValue' error must be returned.

And listen: if a set operation tries to set the value to usmNoAuthProtocol while the usmUserPrivProtocol value in the same row is not equal to usmNoPrivProtocol, then an 'inconsistentValue' error must be returned. That means an SNMP command generator application must first ensure that the usmUserPrivProtocol is set to the usmNoPrivProtocol value before it can set the usmUserAuthProtocol value to usmNoAuthProtocol. Periodt. πŸ”₯


πŸŽ€ usmUserAuthKeyChange

  • SYNTAX KeyChange β€” typically (SIZE (0 | 32)) for HMACMD5, typically (SIZE (0 | 40)) for HMACSHA
  • MAX-ACCESS read-create
  • STATUS current
  • DEFVAL { ''H } β€” the empty string
  • OID ::= { usmUserEntry 6 }

This object is iconic in a very specific way: when it's modified, it causes the secret authentication key used for messages sent on behalf of this user to/from the SNMP engine identified by usmUserEngineID to be modified via a one-way function. 🫢

The associated protocol is the usmUserAuthProtocol. The associated secret key is the user's secret authentication key (authKey). The associated hash algorithm is the algorithm used by the user's usmUserAuthProtocol.

When creating a new user, it's an 'inconsistentName' error for a set operation to refer to this object unless it is previously or concurrently initialized through a set operation on the corresponding instance of usmUserCloneFrom. When the value of the corresponding usmUserAuthProtocol is usmNoAuthProtocol, then a set is successful, but effectively is a no-op. And when this object is read, the zero-length (empty) string is returned.

The recommended way to do a key change is as follows, bestie:

  1. GET(usmUserSpinLock.0) and save in sValue.
  2. Generate the keyChange value based on the old (existing) secret key and the new secret key β€” let's call this kcValue.

If you do the key change on behalf of another user:

3) SET(usmUserSpinLock.0=sValue,
       usmUserAuthKeyChange=kcValue
       usmUserPublic=randomValue)

If you do the key change for yourself:

4) SET(usmUserSpinLock.0=sValue,
       usmUserOwnAuthKeyChange=kcValue
       usmUserPublic=randomValue)

If you get a response with error-status of noError, then the SET succeeded and the new key is active. If you do not get a response, then you can issue a GET(usmUserPublic) and check if the value is equal to the randomValue you did send in the SET. If so, then the key change succeeded and the new key is active β€” probably the response got lost. If not, then the SET request probably never reached the target, so you can start over with the procedure above. πŸ’€


🌸 usmUserOwnAuthKeyChange

  • SYNTAX KeyChange β€” typically (SIZE (0 | 32)) for HMACMD5, typically (SIZE (0 | 40)) for HMACSHA
  • MAX-ACCESS read-create
  • STATUS current
  • DEFVAL { ''H } β€” the empty string
  • OID ::= { usmUserEntry 7 }

This behaves exactly as usmUserAuthKeyChange, with one notable difference: in order for the set operation to succeed, the usmUserName of the operation requester must match the usmUserName that indexes the row which is targeted by this operation. In addition, the USM security model must be used for this operation. πŸ‘‘

The idea here is that access to this column can be public, since it will only allow a user to change his own secret authentication key (authKey). Note that this can only be done once the row is active.

When a set is received and the usmUserName of the requester is not the same as the umsUserName that indexes the row which is targeted by this operation, then a 'noAccess' error must be returned. When a set is received and the security model in use is not USM, then a 'noAccess' error must be returned. Fr fr, that's the vibe check. πŸ¦‹


🌈 usmUserPrivProtocol

  • SYNTAX AutonomousType
  • MAX-ACCESS read-create
  • STATUS current
  • DEFVAL { usmNoPrivProtocol }
  • OID ::= { usmUserEntry 8 }

This object is giving "can we keep a secret?" energy. It's an indication of whether messages sent on behalf of this user to/from the SNMP engine identified by usmUserEngineID can be protected from disclosure β€” and if so, the type of privacy protocol which is used. πŸ’œ

An instance of this object is created concurrently with the creation of any other object instance for the same user. That means as part of the processing of the set operation which creates the first object instance in the same conceptual row, iykyk.

If an initial set operation β€” i.e., at row creation time β€” tries to set a value for an unknown or unsupported protocol, then a 'wrongValue' error must be returned. The value will be overwritten/set when a set operation is performed on the corresponding instance of usmUserCloneFrom.

Once instantiated, the value of such an instance of this object can only be changed via a set operation to the value of usmNoPrivProtocol. If a set operation tries to change the value of an existing instance of this object to any value other than usmNoPrivProtocol, then an 'inconsistentValue' error must be returned.

Important caveat, no cap: if any privacy protocol is used, then you must also use an authentication protocol. In other words, if usmUserPrivProtocol is set to anything else than usmNoPrivProtocol, then the corresponding instance of usmUserAuthProtocol cannot have a value of usmNoAuthProtocol. If it does, then an 'inconsistentValue' error must be returned. Slay with security, bestie. πŸ”


πŸ“ usmUserPrivKeyChange

  • SYNTAX KeyChange β€” typically (SIZE (0 | 32)) for DES
  • MAX-ACCESS read-create
  • STATUS current
  • OID ::= { usmUserEntry 9 }

Wait, actually the page says ::= { usmUserEntry 9 }? No β€” the original ends this chunk before showing the OID, so I'm not adding one here. Let me not invent anything. The visible fields are the syntax, max-access, status, and this description. πŸ’–

This object, when modified, causes the secret encryption key used for messages sent on behalf of this user to/from the SNMP engine identified by usmUserEngineID to be modified via a one-way function.

The associated protocol is the usmUserPrivProtocol. The associated secret key is the user's secret privacy key (privKey). The associated hash algorithm is the algorithm used by the user's usmUserAuthProtocol.

When creating a new user, it is an 'inconsistentName' error for a set operation to refer to this object unless it is previously or concurrently initialized through a set operation on the corresponding instance of usmUserCloneFrom.

When the value of the corresponding usmUserPrivProtocol is usmNoPrivProtocol, then a set is successful, but effectively is a no-op. And that's where this part leaves us β€” mid-vibe, but fully accurate. 🧚

Okay so picking up right in the middle of usmUserOwnAuthKeyChange β€” when you read this object, you get the zero-length (empty) string back. No cap. For the recommended procedure to do a key change, see the description clause of usmUserAuthKeyChange.

  • DEFVAL β€” { ''H } -- the empty string
  • OID β€” ::= { usmUserEntry 9 }

πŸ” usmUserOwnPrivKeyChange

This one behaves exactly like usmUserPrivKeyChange, with one notable difference: for the Set operation to succeed, the usmUserName of the operation requester must match the usmUserName that indexes the row targeted by this operation. Also, the USM security model must be used for this operation.

The whole idea is that access to this column can be public, since it only lets a user change their own secret privacy key (privKey). Note that this can only be done once the row is active.

When a set is received and the usmUserName of the requester is not the same as the umsUserName that indexes the row targeted by this operation, then a 'noAccess' error must be returned. (Yes, the original says umsUserName there β€” typo and all, bestie. πŸ‘€)

When a set is received and the security model in use is not USM, then a 'noAccess' error must be returned.

  • SYNTAX β€” KeyChange -- typically (SIZE (0 | 32)) for DES
  • MAX-ACCESS β€” read-create
  • STATUS β€” current
  • DEFVAL β€” { ''H } -- the empty string
  • OID β€” ::= { usmUserEntry 10 }

🌸 usmUserPublic

A publicly-readable value that you can write as part of the procedure for changing a user's secret authentication and/or privacy key, and then read later to determine whether the change of the secret was actually effected. It's giving "receipt for your secret glow-up." ✨

  • SYNTAX β€” OCTET STRING (SIZE(0..32))
  • MAX-ACCESS β€” read-create
  • STATUS β€” current
  • DEFVAL β€” { ''H } -- the empty string
  • OID β€” ::= { usmUserEntry 11 }

🧚 usmUserStorageType

This is the storage type for this conceptual row.

Conceptual rows that have the value 'permanent' must allow write-access at a minimum to:

  • usmUserAuthKeyChange, usmUserOwnAuthKeyChange and usmUserPublic for a user who employs authentication, and
  • usmUserPrivKeyChange, usmUserOwnPrivKeyChange and usmUserPublic for a user who employs privacy.

Note that any user who employs authentication or privacy must allow its secret(s) to be updated and thus cannot be 'readOnly'.

If an initial set operation tries to set the value to 'readOnly' for a user who employs authentication or privacy, then an 'inconsistentValue' error must be returned. Note that if the value has been previously set (implicit or explicit) to any value, then the rules as defined in the StorageType Textual Convention apply.

It is an implementation issue to decide if a SET for a readOnly or permanent row is accepted at all. In some contexts this may make sense, in others it may not. If a SET for a readOnly or permanent row is not accepted at all, then a 'wrongValue' error must be returned.

  • SYNTAX β€” StorageType
  • MAX-ACCESS β€” read-create
  • STATUS β€” current
  • DEFVAL β€” { nonVolatile }
  • OID β€” ::= { usmUserEntry 12 }

πŸ‘‘ usmUserStatus

The status of this conceptual row.

Until instances of all corresponding columns are appropriately configured, the value of the corresponding instance of the usmUserStatus column is 'notReady'.

In particular, a newly created row for a user who employs authentication cannot be made active until the corresponding usmUserCloneFrom and usmUserAuthKeyChange have been set.

Further, a newly created row for a user who also employs privacy cannot be made active until the usmUserPrivKeyChange has been set.

The RowStatus TC [RFC1903] requires that this DESCRIPTION clause states under which circumstances other objects in this row can be modified:

The value of this object has no effect on whether other objects in this conceptual row can be modified, except for usmUserOwnAuthKeyChange and usmUserOwnPrivKeyChange. For these 2 objects, the value of usmUserStatus MUST be active.

  • SYNTAX β€” RowStatus
  • MAX-ACCESS β€” read-create
  • STATUS β€” current
  • OID β€” ::= { usmUserEntry 13 }

πŸ’… Conformance Information πŸ’…

Original comment line, preserved for the girlies who love exact comments:

-- Conformance Information *******************************************

usmMIBCompliances OBJECT IDENTIFIER ::= { usmMIBConformance 1 }
usmMIBGroups      OBJECT IDENTIFIER ::= { usmMIBConformance 2 }

πŸŽ€ Compliance statements πŸŽ€

usmMIBCompliance

This is the compliance statement for SNMP engines which implement the SNMP-USER-BASED-SM-MIB. Slay.

  • STATUS β€” current
  • MODULE β€” -- this module
  • MANDATORY-GROUPS β€” { usmMIBBasicGroup }
  • OBJECT β€” usmUserAuthProtocol
    • MIN-ACCESS β€” read-only
    • DESCRIPTION β€” write access is not required.
  • OBJECT β€” usmUserPrivProtocol
    • MIN-ACCESS β€” read-only
    • DESCRIPTION β€” write access is not required.
  • OID β€” ::= { usmMIBCompliances 1 }

✨ Units of compliance ✨

usmMIBBasicGroup

A collection of objects providing for configuration of an SNMP engine which implements the SNMP User-based Security Model.

  • OBJECTS β€” the whole iconic lineup:
usmStatsUnsupportedSecLevels,
usmStatsNotInTimeWindows,
usmStatsUnknownUserNames,
usmStatsUnknownEngineIDs,
usmStatsWrongDigests,
usmStatsDecryptionErrors,
usmUserSpinLock,
usmUserSecurityName,
usmUserCloneFrom,
usmUserAuthProtocol,
usmUserAuthKeyChange,
usmUserOwnAuthKeyChange,
usmUserPrivProtocol,
usmUserPrivKeyChange,
usmUserOwnPrivKeyChange,
usmUserPublic,
usmUserStorageType,
usmUserStatus
  • STATUS β€” current
  • OID β€” ::= { usmMIBGroups 1 }

And then the MIB says:

END

Footer vibe check: source/version is Erlang/OTP with SNMP, and the manual page is SNMP-USER-BASED-SM-MIB(7). The footer text I got doesn't show a date, so I'm not inventing one β€” consider this your cute sign-off instead. Byeee πŸ’–πŸ«Ά