snmp_usm_mib_impl.c
Go to the documentation of this file.
1 /**
2  * @file snmp_usm_mib_impl.c
3  * @brief SNMP USM MIB module implementation
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SNMP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "mibs/mib_common.h"
38 #include "mibs/snmp_usm_mib_impl.h"
39 #include "snmp/snmp_agent.h"
40 #include "core/crypto.h"
41 #include "encoding/asn1.h"
42 #include "encoding/oid.h"
43 #include "debug.h"
44 
45 //Check TCP/IP stack configuration
46 #if (SNMP_USM_MIB_SUPPORT == ENABLED)
47 
48 //usmNoAuthProtocol OID (1.3.6.1.6.3.10.1.1.1)
49 const uint8_t usmNoAuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 1};
50 //usmHMACMD5AuthProtocol OID (1.3.6.1.6.3.10.1.1.2)
51 const uint8_t usmHMACMD5AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 2};
52 //usmHMACSHAAuthProtocol OID (1.3.6.1.6.3.10.1.1.3)
53 const uint8_t usmHMACSHAAuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 3};
54 //usmHMAC128SHA224AuthProtocol OID (1.3.6.1.6.3.10.1.1.4)
55 const uint8_t usmHMAC128SHA224AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 4};
56 //usmHMAC192SHA256AuthProtocol OID (1.3.6.1.6.3.10.1.1.5)
57 const uint8_t usmHMAC192SHA256AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 5};
58 //usmHMAC256SHA384AuthProtocol OID (1.3.6.1.6.3.10.1.1.6)
59 const uint8_t usmHMAC256SHA384AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 6};
60 //usmHMAC384SHA512AuthProtocol OID (1.3.6.1.6.3.10.1.1.7)
61 const uint8_t usmHMAC384SHA512AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 7};
62 
63 //usmNoPrivProtocol OID (1.3.6.1.6.3.10.1.2.1)
64 const uint8_t usmNoPrivProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 2, 1};
65 //usmDESPrivProtocol OID (1.3.6.1.6.3.10.1.2.2)
66 const uint8_t usmDESPrivProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 2, 2};
67 //usmAesCfb128Protocol OID (1.3.6.1.6.3.10.1.2.4)
68 const uint8_t usmAesCfb128ProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 2, 4};
69 
70 //usmUserEntry OID (1.3.6.1.6.3.15.1.2.2.1)
71 const uint8_t usmUserEntryOid[10] = {43, 6, 1, 6, 3, 15, 1, 2, 2, 1};
72 
73 
74 /**
75  * @brief SNMP USM MIB module initialization
76  * @return Error code
77  **/
78 
80 {
81  NetContext *context;
82 
83  //Debug message
84  TRACE_INFO("Initializing SNMP-USM-MIB base...\r\n");
85 
86  //Clear SNMP USM MIB base
88 
89  //Point to the TCP/IP stack context
90  context = netGetDefaultContext();
91 
92  //usmUserSpinLock object
93  if(context != NULL)
94  {
95  snmpUsmMibBase.usmUserSpinLock = netGetRandRange(context, 1, INT32_MAX);
96  }
97 
98  //Successful processing
99  return NO_ERROR;
100 }
101 
102 
103 /**
104  * @brief Load SNMP USM MIB module
105  * @param[in] context Pointer to the SNMP agent context
106  * @return Error code
107  **/
108 
109 error_t snmpUsmMibLoad(void *context)
110 {
111  //Register SNMP agent context
112  snmpUsmMibBase.context = context;
113 
114  //Successful processing
115  return NO_ERROR;
116 }
117 
118 
119 /**
120  * @brief Unload SNMP USM MIB module
121  * @param[in] context Pointer to the SNMP agent context
122  **/
123 
124 void snmpUsmMibUnload(void *context)
125 {
126  //Unregister SNMP agent context
127  snmpUsmMibBase.context = NULL;
128 }
129 
130 
131 /**
132  * @brief Lock SNMP USM MIB base
133  **/
134 
135 void snmpUsmMibLock(void)
136 {
137  //Clear temporary user
139 }
140 
141 
142 /**
143  * @brief Unlock SNMP USM MIB base
144  **/
145 
147 {
148  //Clear temporary user
150 }
151 
152 
153 /**
154  * @brief Set usmUserSpinLock object value
155  * @param[in] object Pointer to the MIB object descriptor
156  * @param[in] oid Object identifier (object name and instance identifier)
157  * @param[in] oidLen Length of the OID, in bytes
158  * @param[in] value Object value
159  * @param[in] valueLen Length of the object value, in bytes
160  * @param[in] commit This flag tells whether the changes shall be committed
161  * to the MIB base
162  * @return Error code
163  **/
164 
165 error_t snmpUsmMibSetUserSpinLock(const MibObject *object, const uint8_t *oid,
166  size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
167 {
168  //Test and increment spin lock
170  value->integer, commit);
171 }
172 
173 
174 /**
175  * @brief Get usmUserSpinLock object value
176  * @param[in] object Pointer to the MIB object descriptor
177  * @param[in] oid Object identifier (object name and instance identifier)
178  * @param[in] oidLen Length of the OID, in bytes
179  * @param[out] value Object value
180  * @param[in,out] valueLen Length of the object value, in bytes
181  * @return Error code
182  **/
183 
184 error_t snmpUsmMibGetUserSpinLock(const MibObject *object, const uint8_t *oid,
185  size_t oidLen, MibVariant *value, size_t *valueLen)
186 {
187  //Get the current value of the spin lock
189 
190  //Successful processing
191  return NO_ERROR;
192 }
193 
194 
195 /**
196  * @brief Set usmUserEntry object value
197  * @param[in] object Pointer to the MIB object descriptor
198  * @param[in] oid Object identifier (object name and instance identifier)
199  * @param[in] oidLen Length of the OID, in bytes
200  * @param[in] value Object value
201  * @param[in] valueLen Length of the object value, in bytes
202  * @param[in] commit This flag tells whether the changes shall be committed
203  * to the MIB base
204  * @return Error code
205  **/
206 
207 error_t snmpUsmMibSetUserEntry(const MibObject *object, const uint8_t *oid,
208  size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
209 {
210 #if (SNMP_USM_MIB_SET_SUPPORT == ENABLED)
211  error_t error;
212  size_t n;
213  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
214  size_t userEngineIdLen;
215  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
216  SnmpAgentContext *context;
217  SnmpUserEntry *user;
218 
219  //Point to the instance identifier
220  n = object->oidLen;
221 
222  //usmUserEngineID is used as 1st instance identifier
223  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
224  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
225  //Invalid instance identifier?
226  if(error)
227  return error;
228 
229  //Accept malformed SNMP engine IDs
230  if(n < oidLen && oid[n] == 0)
231  n++;
232 
233  //usmUserName is used as 2nd instance identifier
234  error = mibDecodeString(oid, oidLen, &n, userName,
236  //Invalid instance identifier?
237  if(error)
238  return error;
239 
240  //Sanity check
241  if(n != oidLen)
243 
244  //Make sure the user name is acceptable
245  if(userName[0] == '\0')
247 
248  //Point to the SNMP agent context
250  //Sanity check
251  if(context == NULL)
253 
254  //Retrieve the security profile of the specified user
255  user = snmpFindUserEntry(context, userName, osStrlen(userName));
256 
257  //usmUserCloneFrom object?
258  if(osStrcmp(object->name, "usmUserCloneFrom") == 0)
259  {
260  SnmpUserEntry *cloneFromUser;
261 
262  //Check the length of the OID
263  if(valueLen <= sizeof(usmUserEntryOid))
265 
266  //The OID must point to another conceptual row in the usmUserTable
267  if(osMemcmp(value->oid, usmUserEntryOid, sizeof(usmUserEntryOid)))
269 
270  //Point to the instance identifier
271  n = sizeof(usmUserEntryOid) + 1;
272 
273  //usmUserEngineID is used as 1st instance identifier
274  error = mibDecodeOctetString(value->oid, valueLen, &n, userEngineId,
275  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
276  //Invalid instance identifier?
277  if(error)
278  return error;
279 
280  //usmUserName is used as 2nd instance identifier
281  error = mibDecodeString(value->oid, valueLen, &n, userName,
283  //Invalid instance identifier?
284  if(error)
285  return error;
286 
287  //Retrieve the security profile of the clone-from user
288  cloneFromUser = snmpFindUserEntry(context, userName, osStrlen(userName));
289 
290  //The cloning process fails with an inconsistentName error if the
291  //conceptual row representing the clone-from user does not exist or
292  //is not in an active state when the cloning process is invoked
293  if(cloneFromUser == NULL || cloneFromUser->status != MIB_ROW_STATUS_ACTIVE)
295 
296  //Check whether the row has already been instantiated
297  if(user != NULL)
298  {
299  //Commit phase?
300  if(commit)
301  {
302  //The first time an instance of this object is set by a management
303  //operation, the cloning process is invoked
304  if(user->mode == SNMP_ACCESS_NONE)
305  {
306  //Clone the security parameters of the specified user
307  snmpCloneSecurityParameters(user, cloneFromUser);
308  }
309  }
310  }
311  else
312  {
313  //Prepare phase?
314  if(!commit)
315  {
316  //The first time an instance of this object is set by a management
317  //operation, the cloning process is invoked
319  }
320  }
321  }
322  //usmUserAuthProtocol object?
323  else if(osStrcmp(object->name, "usmUserAuthProtocol") == 0)
324  {
325  //Check whether the user name exists
326  if(user != NULL)
327  {
328  //If a set operation tries to change the value of an existing instance
329  //of this object to any value other than usmNoAuthProtocol, then an
330  //inconsistentValue error must be returned
331  if(oidComp(value->oid, valueLen, usmNoAuthProtocolOid,
332  sizeof(usmNoAuthProtocolOid)))
333  {
335  }
336 
337  //If a set operation tries to set the value to the usmNoAuthProtocol
338  //while the usmUserPrivProtocol value in the same row is not equal to
339  //usmNoPrivProtocol, then an inconsistentValue error must be returned
342 
343  //Commit phase?
344  if(commit)
345  {
346  //Once instantiated, the value of such an instance of this object
347  //can only be changed via a set operation to the value of the
348  //usmNoAuthProtocol
350  }
351  }
352  else
353  {
354  //Prepare phase?
355  if(!commit)
356  {
357  //The usmUserAuthProtocol object specifies the type of authentication
358  //protocol which is used
359  if(OID_COMP(value->oid, valueLen,
360  usmNoAuthProtocolOid) == 0)
361  {
362  //No authentication
363  }
364  else if(OID_COMP(value->oid, valueLen,
366  {
367  //HMAC-MD5-96 authentication protocol
368  }
369  else if(OID_COMP(value->oid, valueLen,
371  {
372  //HMAC-SHA-1-96 authentication protocol
373  }
374  else if(OID_COMP(value->oid, valueLen,
376  {
377  //HMAC-SHA-224-128 authentication protocol
378  }
379  else if(OID_COMP(value->oid, valueLen,
381  {
382  //HMAC-SHA-256-192 authentication protocol
383  }
384  else if(OID_COMP(value->oid, valueLen,
386  {
387  //HMAC-SHA-384-256 authentication protocol
388  }
389  else if(OID_COMP(value->oid, valueLen,
391  {
392  //HMAC-SHA-512-384 authentication protocol
393  }
394  else
395  {
396  //If an initial set operation (at row creation time) tries to
397  //set a value for an unknown or unsupported protocol, then a
398  //wrongValue error must be returned
399  return ERROR_WRONG_VALUE;
400  }
401  }
402  }
403  }
404  //usmUserAuthKeyChange or usmUserOwnAuthKeyChange object?
405  else if(osStrcmp(object->name, "usmUserAuthKeyChange") == 0 ||
406  osStrcmp(object->name, "usmUserOwnAuthKeyChange") == 0)
407  {
408  const HashAlgo *hashAlgo;
409 
410  //Unknown user name?
411  if(user == NULL)
413 
414  //usmUserOwnAuthKeyChange object?
415  if(osStrcmp(object->name, "usmUserOwnAuthKeyChange") == 0)
416  {
417  //When the user name of the requester is not the same as the umsUserName
418  //that indexes the row, then a noAccess error must be returned
419  if(osStrcmp(user->name, context->user.name) != 0)
420  return ERROR_ACCESS_DENIED;
421 
422  //When a set is received and the security model in use is not USM, then
423  //a noAccess error must be returned
424  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
425  return ERROR_ACCESS_DENIED;
426  }
427 
428  //Get the hash algorithm to be used to update the key
429  hashAlgo = snmpGetHashAlgo(user->authProtocol);
430 
431  //Invalid authentication protocol?
432  if(hashAlgo == NULL)
433  return ERROR_WRITE_FAILED;
434 
435  //The value of an instance of this object is the concatenation of
436  //two components of fixed length: first a random component and then
437  //a delta component
438  if(valueLen != (hashAlgo->digestSize * 2))
439  return ERROR_WRONG_LENGTH;
440 
441  //Commit phase?
442  if(commit)
443  {
444  //Update the localized authentication key (Kul)
445  snmpChangeKey(hashAlgo, value->octetString,
446  value->octetString + hashAlgo->digestSize, &user->localizedAuthKey);
447 
448  //The raw authentication key (Ku) is no longer valid
449  osMemset(&user->rawAuthKey, 0, sizeof(SnmpKey));
450  }
451  }
452  //usmUserPrivProtocol object?
453  else if(osStrcmp(object->name, "usmUserPrivProtocol") == 0)
454  {
455  //Check whether the user name exists
456  if(user != NULL)
457  {
458  //If a set operation tries to change the value of an existing instance
459  //of this object to any value other than usmNoPrivProtocol, then an
460  //inconsistentValue error must be returned
461  if(oidComp(value->oid, valueLen, usmNoPrivProtocolOid,
462  sizeof(usmNoPrivProtocolOid)))
463  {
465  }
466 
467  //Commit phase?
468  if(commit)
469  {
470  //Once instantiated, the value of such an instance of this object
471  //can only be changed via a set operation to the value of the
472  //usmNoPrivProtocol
474  }
475  }
476  else
477  {
478  //Prepare phase?
479  if(!commit)
480  {
481  //The usmUserPrivProtocol object specifies the type of privacy
482  //protocol which is used
483  if(OID_COMP(value->oid, valueLen, usmNoPrivProtocolOid) == 0)
484  {
485  //No privacy
486  }
487  else if(OID_COMP(value->oid, valueLen, usmDESPrivProtocolOid) == 0)
488  {
489  //DES-CBC privacy protocol
490  }
491  else if(OID_COMP(value->oid, valueLen, usmAesCfb128ProtocolOid) == 0)
492  {
493  //AES-128-CFB privacy protocol
494  }
495  else
496  {
497  //If an initial set operation (at row creation time) tries to
498  //set a value for an unknown or unsupported protocol, then a
499  //wrongValue error must be returned
500  return ERROR_WRONG_VALUE;
501  }
502  }
503  }
504  }
505  //usmUserPrivKeyChange or usmUserOwnPrivKeyChangeobject?
506  else if(osStrcmp(object->name, "usmUserPrivKeyChange") == 0 ||
507  osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
508  {
509  const HashAlgo *hashAlgo;
510 
511  //Unknown user name?
512  if(user == NULL)
514 
515  //usmUserOwnPrivKeyChange object?
516  if(osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
517  {
518  //When the user name of the requester is not the same as the umsUserName
519  //that indexes the row, then a noAccess error must be returned
520  if(osStrcmp(user->name, context->user.name) != 0)
521  return ERROR_ACCESS_DENIED;
522 
523  //When a set is received and the security model in use is not USM, then
524  //a noAccess error must be returned
525  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
526  return ERROR_ACCESS_DENIED;
527  }
528 
529  //Get the hash algorithm to be used to update the key
530  hashAlgo = snmpGetHashAlgo(user->authProtocol);
531 
532  //Invalid authentication protocol?
533  if(hashAlgo == NULL)
534  return ERROR_WRITE_FAILED;
535 
536  //The value of an instance of this object is the concatenation of
537  //two components of fixed length: first a random component and then
538  //a delta component
539  if(valueLen != (hashAlgo->digestSize * 2))
540  return ERROR_WRONG_LENGTH;
541 
542  //Commit phase?
543  if(commit)
544  {
545  //Update the localized privacy key (Kul)
546  snmpChangeKey(hashAlgo, value->octetString,
547  value->octetString + hashAlgo->digestSize, &user->localizedPrivKey);
548 
549  //The raw privacy key (Ku) is no longer valid
550  osMemset(&user->rawPrivKey, 0, sizeof(SnmpKey));
551  }
552  }
553  //usmUserPublic object?
554  else if(osStrcmp(object->name, "usmUserPublic") == 0)
555  {
556  //Check the length of the public value
557  if(valueLen > SNMP_MAX_PUBLIC_VALUE_SIZE)
558  return ERROR_WRONG_LENGTH;
559 
560  //Check whether the user name exists
561  if(user != NULL)
562  {
563  //Commit phase?
564  if(commit)
565  {
566  //The usmUserPublic can be written as part of the procedure for
567  //changing a user's secret authentication and/or privacy key,
568  //and later read to determine whether the change of the secret
569  //was effected
570  osMemcpy(user->publicValue, value->octetString, valueLen);
571 
572  //Update the length of the public value
573  user->publicValueLen = valueLen;
574  }
575  }
576  else
577  {
578  //Prepare phase?
579  if(!commit)
580  {
581  //Save the value of the public value for later use
583  valueLen);
584 
585  //Save the length of the public value
587  }
588  }
589  }
590  //usmUserStorageType object?
591  else if(osStrcmp(object->name, "usmUserStorageType") == 0)
592  {
593  //The usmUserStorageType object specifies the storage type for this
594  //conceptual row
595  if(value->integer != MIB_STORAGE_TYPE_OTHER &&
596  value->integer != MIB_STORAGE_TYPE_VOLATILE &&
597  value->integer != MIB_STORAGE_TYPE_NON_VOLATILE &&
598  value->integer != MIB_STORAGE_TYPE_PERMANENT &&
599  value->integer != MIB_STORAGE_TYPE_READ_ONLY)
600  {
601  return ERROR_WRONG_VALUE;
602  }
603  }
604  //usmUserStatus object?
605  else if(osStrcmp(object->name, "usmUserStatus") == 0)
606  {
607  MibRowStatus status;
608 
609  //Get row status
610  status = (MibRowStatus) value->integer;
611 
612  //Check the value specified by the set operation
613  if(status == MIB_ROW_STATUS_ACTIVE ||
615  {
616  //Unknown user name?
617  if(user == NULL)
619 
620  //Commit phase?
621  if(commit)
622  {
623  //The first time an instance of this object is set by a management
624  //operation, the cloning process is invoked
625  if(user->mode == SNMP_ACCESS_NONE)
626  {
627  //Valid clone-from user?
629  {
630  //Copy the security profile of the clone-from user
632  }
633  }
634 
635  //When the agent processes the set operation, it verifies that it
636  //has sufficient information to make the conceptual row available
637  //for use by the managed device
638  if(user->mode == SNMP_ACCESS_NONE)
640 
641  //Update the status of the conceptual row
642  user->status = status;
643  }
644  }
645  else if(status == MIB_ROW_STATUS_CREATE_AND_GO)
646  {
647  //User name already in use?
648  if(user != NULL)
650 
651  //Create a security profile for the new user
652  user = snmpCreateUserEntry(context);
653  //Unable to create a new user?
654  if(user == NULL)
655  return ERROR_WRITE_FAILED;
656 
657  //Commit phase?
658  if(commit)
659  {
660  //Valid clone-from user?
662  {
663  //Clear the security profile of the user
664  osMemset(user, 0, sizeof(SnmpUserEntry));
665  //Save user name
666  osStrcpy(user->name, userName);
667 
668  //Valid public value specified?
670  {
671  //Copy the public value
674 
675  //Set the length of the public value
677  }
678 
679  //Copy the security profile of the clone-from user
681 
682  //The conceptual row is now available for use by the managed device
684  }
685  else
686  {
687  //The newly created row cannot be made active
689  }
690  }
691  }
692  else if(status == MIB_ROW_STATUS_CREATE_AND_WAIT)
693  {
694  //User name already in use?
695  if(user != NULL)
697 
698  //Create a security profile for the new user
699  user = snmpCreateUserEntry(context);
700  //Unable to create a new user?
701  if(user == NULL)
702  return ERROR_WRITE_FAILED;
703 
704  //Commit phase?
705  if(commit)
706  {
707  //Clear the security profile of the user
708  osMemset(user, 0, sizeof(SnmpUserEntry));
709  //Save user name
710  osStrcpy(user->name, userName);
711 
712  //Valid public value specified?
714  {
715  //Copy the public value
718 
719  //Set the length of the public value
721  }
722 
723  //Check whether the cloning process has been invoked
724  if(user->mode != SNMP_ACCESS_NONE)
725  {
726  //Copy the security profile of the clone-from user
728 
729  //Instances of all corresponding columns are now configured
731  }
732  else
733  {
734  //Initialize columns with default values
737 
738  //Until instances of all corresponding columns are appropriately
739  //configured, the value of the corresponding instance of the
740  //usmUserStatus column is notReady
742  }
743  }
744  }
745  else if(status == MIB_ROW_STATUS_DESTROY)
746  {
747  //Check whether the user name exists
748  if(user != NULL)
749  {
750  //Commit phase?
751  if(commit)
752  {
753  //Clear the security profile of the user
754  osMemset(user, 0, sizeof(SnmpUserEntry));
755 
756  //Delete the conceptual row from the table
758  }
759  }
760  }
761  else
762  {
763  //Unsupported action
765  }
766  }
767  //Unknown object?
768  else
769  {
770  //The specified object does not exist
771  return ERROR_OBJECT_NOT_FOUND;
772  }
773 
774  //Successful processing
775  return NO_ERROR;
776 #else
777  //SET operation is not supported
778  return ERROR_WRITE_FAILED;
779 #endif
780 }
781 
782 
783 /**
784  * @brief Get usmUserEntry object value
785  * @param[in] object Pointer to the MIB object descriptor
786  * @param[in] oid Object identifier (object name and instance identifier)
787  * @param[in] oidLen Length of the OID, in bytes
788  * @param[out] value Object value
789  * @param[in,out] valueLen Length of the object value, in bytes
790  * @return Error code
791  **/
792 
793 error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid,
794  size_t oidLen, MibVariant *value, size_t *valueLen)
795 {
796  error_t error;
797  size_t n;
798  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
799  size_t userEngineIdLen;
800  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
801  SnmpAgentContext *context;
802  SnmpUserEntry *user;
803 
804  //Point to the instance identifier
805  n = object->oidLen;
806 
807  //usmUserEngineID is used as 1st instance identifier
808  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
809  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
810  //Invalid instance identifier?
811  if(error)
812  return error;
813 
814  //usmUserName is used as 2nd instance identifier
815  error = mibDecodeString(oid, oidLen, &n, userName,
817  //Invalid instance identifier?
818  if(error)
819  return error;
820 
821  //Sanity check
822  if(n != oidLen)
824 
825  //Point to the SNMP agent context
827  //Sanity check
828  if(context == NULL)
830 
831  //Check the length of the SNMP engine ID
832  if(userEngineIdLen != context->contextEngineLen)
834 
835  //Check SNMP engine ID
836  if(osMemcmp(userEngineId, context->contextEngine, userEngineIdLen))
838 
839  //Retrieve the security profile of the specified user
840  user = snmpFindUserEntry(context, userName, osStrlen(userName));
841  //Unknown user name?
842  if(user == NULL)
844 
845  //usmUserSecurityName object?
846  if(osStrcmp(object->name, "usmUserSecurityName") == 0)
847  {
848  //The security name is the same as the user name
849  n = osStrlen(user->name);
850 
851  //Make sure the buffer is large enough to hold the entire object
852  if(*valueLen >= n)
853  {
854  //Copy object value
855  osMemcpy(value->octetString, user->name, n);
856  //Return object length
857  *valueLen = n;
858  }
859  else
860  {
861  //Report an error
862  error = ERROR_BUFFER_OVERFLOW;
863  }
864  }
865  //usmUserCloneFrom object?
866  else if(osStrcmp(object->name, "usmUserCloneFrom") == 0)
867  {
868  //When this object is read, the ZeroDotZero OID is returned
869  uint8_t zeroDotZeroOid[] = {0};
870 
871  //Make sure the buffer is large enough to hold the entire object
872  if(*valueLen >= sizeof(zeroDotZeroOid))
873  {
874  //Copy object value
875  osMemcpy(value->octetString, zeroDotZeroOid, sizeof(zeroDotZeroOid));
876  //Return object length
877  *valueLen = sizeof(zeroDotZeroOid);
878  }
879  else
880  {
881  //Report an error
882  error = ERROR_BUFFER_OVERFLOW;
883  }
884  }
885  //usmUserAuthProtocol object?
886  else if(osStrcmp(object->name, "usmUserAuthProtocol") == 0)
887  {
888  size_t authProtocolLen;
889  const uint8_t *authProtocol;
890 
891  //Check the type of authentication protocol which is used
892  switch(user->authProtocol)
893  {
894  //HMAC-MD5-96 authentication protocol?
896  authProtocol = usmHMACMD5AuthProtocolOid;
897  authProtocolLen = sizeof(usmHMACMD5AuthProtocolOid);
898  break;
899  //HMAC-SHA-1-96 authentication protocol?
901  authProtocol = usmHMACSHAAuthProtocolOid;
902  authProtocolLen = sizeof(usmHMACSHAAuthProtocolOid);
903  break;
904  //HMAC-SHA-224-128 authentication protocol?
906  authProtocol = usmHMAC128SHA224AuthProtocolOid;
907  authProtocolLen = sizeof(usmHMAC128SHA224AuthProtocolOid);
908  break;
909  //HMAC-SHA-256-192 authentication protocol?
911  authProtocol = usmHMAC192SHA256AuthProtocolOid;
912  authProtocolLen = sizeof(usmHMAC192SHA256AuthProtocolOid);
913  break;
914  //HMAC-SHA-384-256 authentication protocol?
916  authProtocol = usmHMAC256SHA384AuthProtocolOid;
917  authProtocolLen = sizeof(usmHMAC256SHA384AuthProtocolOid);
918  break;
919  //HMAC-SHA-512-384 authentication protocol?
921  authProtocol = usmHMAC384SHA512AuthProtocolOid;
922  authProtocolLen = sizeof(usmHMAC384SHA512AuthProtocolOid);
923  break;
924  //No authentication?
925  default:
926  authProtocol = usmNoAuthProtocolOid;
927  authProtocolLen = sizeof(usmNoAuthProtocolOid);
928  break;
929  }
930 
931  //Make sure the buffer is large enough to hold the entire object
932  if(*valueLen >= authProtocolLen)
933  {
934  //Copy object value
935  osMemcpy(value->octetString, authProtocol, authProtocolLen);
936  //Return object length
937  *valueLen = authProtocolLen;
938  }
939  else
940  {
941  //Report an error
942  error = ERROR_BUFFER_OVERFLOW;
943  }
944  }
945  //usmUserAuthKeyChange object?
946  else if(osStrcmp(object->name, "usmUserAuthKeyChange") == 0)
947  {
948  //When this object is read, the zero-length (empty) string is returned
949  *valueLen = 0;
950  }
951  //usmUserOwnAuthKeyChange object?
952  else if(osStrcmp(object->name, "usmUserOwnAuthKeyChange") == 0)
953  {
954  //When this object is read, the zero-length (empty) string is returned
955  *valueLen = 0;
956  }
957  //usmUserPrivProtocol object?
958  else if(osStrcmp(object->name, "usmUserPrivProtocol") == 0)
959  {
960  size_t privProtocolLen;
961  const uint8_t *privProtocol;
962 
963  //Check the type of privacy protocol which is used
964  switch(user->privProtocol)
965  {
966  //DES-CBC privacy protocol?
968  privProtocol = usmDESPrivProtocolOid;
969  privProtocolLen = sizeof(usmDESPrivProtocolOid);
970  break;
971  //AES-128-CFB privacy protocol?
973  privProtocol = usmAesCfb128ProtocolOid;
974  privProtocolLen = sizeof(usmAesCfb128ProtocolOid);
975  break;
976  //No privacy?
977  default:
978  privProtocol = usmNoPrivProtocolOid;
979  privProtocolLen = sizeof(usmNoPrivProtocolOid);
980  break;
981  }
982 
983  //Make sure the buffer is large enough to hold the entire object
984  if(*valueLen >= privProtocolLen)
985  {
986  //Copy object value
987  osMemcpy(value->octetString, privProtocol, privProtocolLen);
988  //Return object length
989  *valueLen = privProtocolLen;
990  }
991  else
992  {
993  //Report an error
994  error = ERROR_BUFFER_OVERFLOW;
995  }
996  }
997  //usmUserPrivKeyChange object?
998  else if(osStrcmp(object->name, "usmUserPrivKeyChange") == 0)
999  {
1000  //When this object is read, the zero-length (empty) string is returned
1001  *valueLen = 0;
1002  }
1003  //usmUserOwnPrivKeyChange object?
1004  else if(osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
1005  {
1006  //When this object is read, the zero-length (empty) string is returned
1007  *valueLen = 0;
1008  }
1009  //usmUserPublic object?
1010  else if(osStrcmp(object->name, "usmUserPublic") == 0)
1011  {
1012  //Make sure the buffer is large enough to hold the public value
1013  if(*valueLen >= user->publicValueLen)
1014  {
1015  //The public value can be read to determine whether the change of
1016  //the secret was effected
1017  osMemcpy(value->octetString, user->publicValue, user->publicValueLen);
1018 
1019  //Return object length
1020  *valueLen = user->publicValueLen;
1021  }
1022  else
1023  {
1024  //Report an error
1025  error = ERROR_BUFFER_OVERFLOW;
1026  }
1027  }
1028  //usmUserStorageType object?
1029  else if(osStrcmp(object->name, "usmUserStorageType") == 0)
1030  {
1031  //Get the storage type for this conceptual row
1032  value->integer = MIB_STORAGE_TYPE_VOLATILE;
1033  }
1034  //usmUserStatus object?
1035  else if(osStrcmp(object->name, "usmUserStatus") == 0)
1036  {
1037  //Get the status of this conceptual row
1038  value->integer = user->status;
1039  }
1040  //Unknown object?
1041  else
1042  {
1043  //The specified object does not exist
1044  error = ERROR_OBJECT_NOT_FOUND;
1045  }
1046 
1047  //Return status code
1048  return error;
1049 }
1050 
1051 
1052 /**
1053  * @brief Get next usmUserEntry object
1054  * @param[in] object Pointer to the MIB object descriptor
1055  * @param[in] oid Object identifier
1056  * @param[in] oidLen Length of the OID, in bytes
1057  * @param[out] nextOid OID of the next object in the MIB
1058  * @param[out] nextOidLen Length of the next object identifier, in bytes
1059  * @return Error code
1060  **/
1061 
1062 error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid,
1063  size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
1064 {
1065  error_t error;
1066  uint_t i;
1067  size_t n;
1068  bool_t acceptable;
1069  SnmpAgentContext *context;
1070  SnmpUserEntry *entry;
1071  SnmpUserEntry *nextEntry;
1072 
1073  //Initialize variables
1074  nextEntry = NULL;
1075 
1076  //Point to the SNMP agent context
1077  context = (SnmpAgentContext *) snmpUsmMibBase.context;
1078  //Sanity check
1079  if(context == NULL)
1080  return ERROR_OBJECT_NOT_FOUND;
1081 
1082  //Make sure the buffer is large enough to hold the OID prefix
1083  if(*nextOidLen < object->oidLen)
1084  return ERROR_BUFFER_OVERFLOW;
1085 
1086  //Copy OID prefix
1087  osMemcpy(nextOid, object->oid, object->oidLen);
1088 
1089  //Loop through the list of users
1090  for(i = 0; i < SNMP_AGENT_MAX_USERS; i++)
1091  {
1092  //Point to the current entry
1093  entry = &context->userTable[i];
1094 
1095  //Check the status of the row
1096  if(entry->status != MIB_ROW_STATUS_UNUSED)
1097  {
1098  //Append the instance identifier to the OID prefix
1099  n = object->oidLen;
1100 
1101  //usmUserEngineID is used as 1st instance identifier
1102  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1103  context->contextEngine, context->contextEngineLen, FALSE);
1104  //Any error to report?
1105  if(error)
1106  return error;
1107 
1108  //usmUserName is used as 2nd instance identifier
1109  error = mibEncodeString(nextOid, *nextOidLen, &n, entry->name, FALSE);
1110  //Any error to report?
1111  if(error)
1112  return error;
1113 
1114  //Check whether the resulting object identifier lexicographically
1115  //follows the specified OID
1116  if(oidComp(nextOid, n, oid, oidLen) > 0)
1117  {
1118  //Perform lexicographic comparison
1119  if(nextEntry == NULL)
1120  {
1121  acceptable = TRUE;
1122  }
1123  else if(osStrlen(entry->name) < osStrlen(nextEntry->name))
1124  {
1125  acceptable = TRUE;
1126  }
1127  else if(osStrlen(entry->name) > osStrlen(nextEntry->name))
1128  {
1129  acceptable = FALSE;
1130  }
1131  else if(osStrcmp(entry->name, nextEntry->name) < 0)
1132  {
1133  acceptable = TRUE;
1134  }
1135  else
1136  {
1137  acceptable = FALSE;
1138  }
1139 
1140  //Save the closest object identifier that follows the specified
1141  //OID in lexicographic order
1142  if(acceptable)
1143  nextEntry = entry;
1144  }
1145  }
1146  }
1147 
1148  //The specified OID does not lexicographically precede the name
1149  //of some object?
1150  if(nextEntry == NULL)
1151  return ERROR_OBJECT_NOT_FOUND;
1152 
1153  //Append the instance identifier to the OID prefix
1154  n = object->oidLen;
1155 
1156  //usmUserEngineID is used as 1st instance identifier
1157  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1158  context->contextEngine, context->contextEngineLen, FALSE);
1159  //Any error to report?
1160  if(error)
1161  return error;
1162 
1163  //usmUserName is used as 2nd instance identifier
1164  error = mibEncodeString(nextOid, *nextOidLen, &n, nextEntry->name, FALSE);
1165  //Any error to report?
1166  if(error)
1167  return error;
1168 
1169  //Save the length of the resulting object identifier
1170  *nextOidLen = n;
1171  //Next object found
1172  return NO_ERROR;
1173 }
1174 
1175 #endif
@ MIB_ROW_STATUS_NOT_IN_SERVICE
Definition: mib_common.h:104
error_t mibEncodeString(uint8_t *oid, size_t maxOidLen, size_t *pos, const char_t *string, bool_t implied)
Encode instance identifier (string)
Definition: mib_common.c:129
@ SNMP_AUTH_PROTOCOL_MD5
HMAC-MD5-96.
#define NetContext
Definition: net.h:36
int bool_t
Definition: compiler_port.h:63
@ MIB_ROW_STATUS_CREATE_AND_GO
Definition: mib_common.h:106
@ MIB_STORAGE_TYPE_NON_VOLATILE
Definition: mib_common.h:120
uint8_t publicValue[SNMP_MAX_PUBLIC_VALUE_SIZE]
Public value.
SnmpKey localizedPrivKey
Localized privacy key.
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:143
@ SNMP_AUTH_PROTOCOL_SHA224
HMAC-SHA-224-128.
SnmpAccess mode
Access mode.
OID (Object Identifier)
uint32_t netGetRandRange(NetContext *context, uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net.c:473
const uint8_t usmHMAC384SHA512AuthProtocolOid[9]
#define SNMP_AGENT_MAX_USERS
Definition: snmp_agent.h:83
@ MIB_STORAGE_TYPE_OTHER
Definition: mib_common.h:118
#define TRUE
Definition: os_port.h:50
SnmpUserEntry tempUser
size_t digestSize
Definition: crypto.h:1157
@ SNMP_AUTH_PROTOCOL_SHA384
HMAC-SHA-384-256.
#define osMemcmp(p1, p2, length)
Definition: os_port.h:156
@ SNMP_SECURITY_MODEL_USM
User-based security model.
#define osStrcmp(s1, s2)
Definition: os_port.h:174
#define osStrlen(s)
Definition: os_port.h:168
User table entry.
const uint8_t usmUserEntryOid[10]
@ MIB_ROW_STATUS_NOT_READY
Definition: mib_common.h:105
int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2, size_t oidLen2)
Compare object identifiers.
Definition: oid.c:103
@ MIB_ROW_STATUS_DESTROY
Definition: mib_common.h:108
uint8_t oid[]
Definition: lldp_tlv.h:300
@ MIB_STORAGE_TYPE_READ_ONLY
Definition: mib_common.h:122
SNMP agent (Simple Network Management Protocol)
error_t snmpUsmMibLoad(void *context)
Load SNMP USM MIB module.
void snmpCloneSecurityParameters(SnmpUserEntry *user, const SnmpUserEntry *cloneFromUser)
Clone security parameters.
SnmpUserEntry * snmpCreateUserEntry(SnmpAgentContext *context)
Create a new user entry.
const uint8_t usmHMACMD5AuthProtocolOid[9]
size_t publicValueLen
Length of the public value.
SnmpKey localizedAuthKey
Localized authentication key.
error_t snmpUsmMibGetUserSpinLock(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen)
Get usmUserSpinLock object value.
#define FALSE
Definition: os_port.h:46
error_t snmpUsmMibSetUserEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
Set usmUserEntry object value.
SnmpUsmMibBase snmpUsmMibBase
SNMP USM MIB base.
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
@ SNMP_PRIV_PROTOCOL_NONE
No privacy.
error_t
Error codes.
Definition: error.h:43
@ ERROR_INSTANCE_NOT_FOUND
Definition: error.h:258
const uint8_t usmHMAC192SHA256AuthProtocolOid[9]
#define SNMP_MAX_USER_NAME_LEN
Definition: snmp_common.h:81
SnmpUserEntry * snmpFindUserEntry(SnmpAgentContext *context, const char_t *name, size_t length)
Search the user table for a given user name.
const uint8_t usmHMAC128SHA224AuthProtocolOid[9]
const uint8_t usmHMACSHAAuthProtocolOid[9]
@ SNMP_AUTH_PROTOCOL_SHA256
HMAC-SHA-256-192.
@ MIB_ROW_STATUS_UNUSED
Definition: mib_common.h:102
void snmpUsmMibUnlock(void)
Unlock SNMP USM MIB base.
const HashAlgo * snmpGetHashAlgo(SnmpAuthProtocol authProtocol)
Get the hash algorithm to be used for a given authentication protocol.
General definitions for cryptographic algorithms.
NetContext * netGetDefaultContext(void)
Get default TCP/IP stack context.
Definition: net.c:527
const uint8_t usmNoPrivProtocolOid[9]
@ SNMP_AUTH_PROTOCOL_SHA1
HMAC-SHA-1-96.
@ SNMP_AUTH_PROTOCOL_SHA512
HMAC-SHA-512-384.
@ ERROR_ACCESS_DENIED
Definition: error.h:149
const uint8_t usmHMAC256SHA384AuthProtocolOid[9]
@ ERROR_WRONG_LENGTH
Definition: error.h:120
#define TRACE_INFO(...)
Definition: debug.h:105
void snmpUsmMibUnload(void *context)
Unload SNMP USM MIB module.
#define SNMP_MAX_PUBLIC_VALUE_SIZE
Definition: snmp_common.h:88
error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
Get next usmUserEntry object.
MibRowStatus status
Status of the user.
error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen)
Get usmUserEntry object value.
void snmpChangeKey(const HashAlgo *hashAlgo, const uint8_t *random, const uint8_t *delta, SnmpKey *key)
Change secret key.
SNMP secret key.
char char_t
Definition: compiler_port.h:55
@ MIB_ROW_STATUS_ACTIVE
Definition: mib_common.h:103
error_t mibEncodeOctetString(uint8_t *oid, size_t maxOidLen, size_t *pos, const uint8_t *data, size_t dataLen, bool_t implied)
Encode instance identifier (octet string)
Definition: mib_common.c:182
SnmpAuthProtocol authProtocol
Authentication protocol.
char_t name[SNMP_MAX_USER_NAME_LEN+1]
User name.
#define OID_COMP(oid1, oidLen1, oid2)
Definition: oid.h:42
MibRowStatus
Row status.
Definition: mib_common.h:101
Common definitions for MIB modules.
uint8_t n
@ ERROR_WRONG_VALUE
Definition: error.h:123
@ SNMP_ACCESS_NONE
@ ERROR_WRITE_FAILED
Definition: error.h:223
@ ERROR_OBJECT_NOT_FOUND
Definition: error.h:257
SNMP USM MIB module implementation.
const uint8_t usmNoAuthProtocolOid[9]
error_t snmpUsmMibInit(void)
SNMP USM MIB module initialization.
#define MibObject
Definition: mib_common.h:46
uint8_t value[]
Definition: tcp.h:376
SnmpKey rawAuthKey
Raw authentication key.
uint8_t oidLen
Definition: lldp_tlv.h:299
error_t snmpUsmMibSetUserSpinLock(const MibObject *object, const uint8_t *oid, size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
Set usmUserSpinLock object value.
@ MIB_ROW_STATUS_CREATE_AND_WAIT
Definition: mib_common.h:107
@ MIB_STORAGE_TYPE_VOLATILE
Definition: mib_common.h:119
SnmpPrivProtocol privProtocol
Privacy protocol.
#define SNMP_MAX_CONTEXT_ENGINE_SIZE
Definition: snmp_common.h:67
#define SnmpAgentContext
Definition: snmp_agent.h:36
const uint8_t usmAesCfb128ProtocolOid[9]
Common interface for hash algorithms.
Definition: crypto.h:1151
SNMP USM MIB module.
error_t mibTestAndIncSpinLock(int32_t *spinLock, int32_t value, bool_t commit)
Test and increment spin lock.
Definition: mib_common.c:1006
error_t mibDecodeString(const uint8_t *oid, size_t oidLen, size_t *pos, char_t *string, size_t maxStringLen, bool_t implied)
Decode instance identifier (string)
Definition: mib_common.c:149
MibVariant
Definition: mib_common.h:196
@ SNMP_PRIV_PROTOCOL_AES
AES-128-CFB.
unsigned int uint_t
Definition: compiler_port.h:57
SnmpAgentContext * context
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
@ SNMP_AUTH_PROTOCOL_NONE
No authentication.
error_t mibDecodeOctetString(const uint8_t *oid, size_t oidLen, size_t *pos, uint8_t *data, size_t maxDataLen, size_t *dataLen, bool_t implied)
Decode instance identifier (octet string)
Definition: mib_common.c:225
#define osStrcpy(s1, s2)
Definition: os_port.h:210
@ SNMP_PRIV_PROTOCOL_DES
DES-CBC.
SnmpKey rawPrivKey
Raw privacy key.
const uint8_t usmDESPrivProtocolOid[9]
@ ERROR_INCONSISTENT_VALUE
Definition: error.h:124
@ NO_ERROR
Success.
Definition: error.h:44
void snmpUsmMibLock(void)
Lock SNMP USM MIB base.
Debugging facilities.
ASN.1 (Abstract Syntax Notation One)
@ MIB_STORAGE_TYPE_PERMANENT
Definition: mib_common.h:121