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-2025 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.5.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  //Debug message
82  TRACE_INFO("Initializing SNMP-USM-MIB base...\r\n");
83 
84  //Clear SNMP USM MIB base
86 
87  //usmUserSpinLock object
89 
90  //Successful processing
91  return NO_ERROR;
92 }
93 
94 
95 /**
96  * @brief Load SNMP USM MIB module
97  * @param[in] context Pointer to the SNMP agent context
98  * @return Error code
99  **/
100 
101 error_t snmpUsmMibLoad(void *context)
102 {
103  //Register SNMP agent context
104  snmpUsmMibBase.context = context;
105 
106  //Successful processing
107  return NO_ERROR;
108 }
109 
110 
111 /**
112  * @brief Unload SNMP USM MIB module
113  * @param[in] context Pointer to the SNMP agent context
114  **/
115 
116 void snmpUsmMibUnload(void *context)
117 {
118  //Unregister SNMP agent context
119  snmpUsmMibBase.context = NULL;
120 }
121 
122 
123 /**
124  * @brief Lock SNMP USM MIB base
125  **/
126 
127 void snmpUsmMibLock(void)
128 {
129  //Clear temporary user
131 }
132 
133 
134 /**
135  * @brief Unlock SNMP USM MIB base
136  **/
137 
139 {
140  //Clear temporary user
142 }
143 
144 
145 /**
146  * @brief Set usmUserSpinLock object value
147  * @param[in] object Pointer to the MIB object descriptor
148  * @param[in] oid Object identifier (object name and instance identifier)
149  * @param[in] oidLen Length of the OID, in bytes
150  * @param[in] value Object value
151  * @param[in] valueLen Length of the object value, in bytes
152  * @param[in] commit This flag tells whether the changes shall be committed
153  * to the MIB base
154  * @return Error code
155  **/
156 
157 error_t snmpUsmMibSetUserSpinLock(const MibObject *object, const uint8_t *oid,
158  size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
159 {
160  //Test and increment spin lock
162  value->integer, commit);
163 }
164 
165 
166 /**
167  * @brief Get usmUserSpinLock object value
168  * @param[in] object Pointer to the MIB object descriptor
169  * @param[in] oid Object identifier (object name and instance identifier)
170  * @param[in] oidLen Length of the OID, in bytes
171  * @param[out] value Object value
172  * @param[in,out] valueLen Length of the object value, in bytes
173  * @return Error code
174  **/
175 
176 error_t snmpUsmMibGetUserSpinLock(const MibObject *object, const uint8_t *oid,
177  size_t oidLen, MibVariant *value, size_t *valueLen)
178 {
179  //Get the current value of the spin lock
181 
182  //Successful processing
183  return NO_ERROR;
184 }
185 
186 
187 /**
188  * @brief Set usmUserEntry object value
189  * @param[in] object Pointer to the MIB object descriptor
190  * @param[in] oid Object identifier (object name and instance identifier)
191  * @param[in] oidLen Length of the OID, in bytes
192  * @param[in] value Object value
193  * @param[in] valueLen Length of the object value, in bytes
194  * @param[in] commit This flag tells whether the changes shall be committed
195  * to the MIB base
196  * @return Error code
197  **/
198 
199 error_t snmpUsmMibSetUserEntry(const MibObject *object, const uint8_t *oid,
200  size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
201 {
202 #if (SNMP_USM_MIB_SET_SUPPORT == ENABLED)
203  error_t error;
204  size_t n;
205  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
206  size_t userEngineIdLen;
207  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
208  SnmpAgentContext *context;
209  SnmpUserEntry *user;
210 
211  //Point to the instance identifier
212  n = object->oidLen;
213 
214  //usmUserEngineID is used as 1st instance identifier
215  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
216  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
217  //Invalid instance identifier?
218  if(error)
219  return error;
220 
221  //Accept malformed SNMP engine IDs
222  if(n < oidLen && oid[n] == 0)
223  n++;
224 
225  //usmUserName is used as 2nd instance identifier
226  error = mibDecodeString(oid, oidLen, &n, userName,
228  //Invalid instance identifier?
229  if(error)
230  return error;
231 
232  //Sanity check
233  if(n != oidLen)
235 
236  //Make sure the user name is acceptable
237  if(userName[0] == '\0')
239 
240  //Point to the SNMP agent context
242  //Sanity check
243  if(context == NULL)
245 
246  //Retrieve the security profile of the specified user
247  user = snmpFindUserEntry(context, userName, osStrlen(userName));
248 
249  //usmUserCloneFrom object?
250  if(osStrcmp(object->name, "usmUserCloneFrom") == 0)
251  {
252  SnmpUserEntry *cloneFromUser;
253 
254  //Check the length of the OID
255  if(valueLen <= sizeof(usmUserEntryOid))
257 
258  //The OID must point to another conceptual row in the usmUserTable
259  if(osMemcmp(value->oid, usmUserEntryOid, sizeof(usmUserEntryOid)))
261 
262  //Point to the instance identifier
263  n = sizeof(usmUserEntryOid) + 1;
264 
265  //usmUserEngineID is used as 1st instance identifier
266  error = mibDecodeOctetString(value->oid, valueLen, &n, userEngineId,
267  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
268  //Invalid instance identifier?
269  if(error)
270  return error;
271 
272  //usmUserName is used as 2nd instance identifier
273  error = mibDecodeString(value->oid, valueLen, &n, userName,
275  //Invalid instance identifier?
276  if(error)
277  return error;
278 
279  //Retrieve the security profile of the clone-from user
280  cloneFromUser = snmpFindUserEntry(context, userName, osStrlen(userName));
281 
282  //The cloning process fails with an inconsistentName error if the
283  //conceptual row representing the clone-from user does not exist or
284  //is not in an active state when the cloning process is invoked
285  if(cloneFromUser == NULL || cloneFromUser->status != MIB_ROW_STATUS_ACTIVE)
287 
288  //Check whether the row has already been instantiated
289  if(user != NULL)
290  {
291  //Commit phase?
292  if(commit)
293  {
294  //The first time an instance of this object is set by a management
295  //operation, the cloning process is invoked
296  if(user->mode == SNMP_ACCESS_NONE)
297  {
298  //Clone the security parameters of the specified user
299  snmpCloneSecurityParameters(user, cloneFromUser);
300  }
301  }
302  }
303  else
304  {
305  //Prepare phase?
306  if(!commit)
307  {
308  //The first time an instance of this object is set by a management
309  //operation, the cloning process is invoked
311  }
312  }
313  }
314  //usmUserAuthProtocol object?
315  else if(osStrcmp(object->name, "usmUserAuthProtocol") == 0)
316  {
317  //Check whether the user name exists
318  if(user != NULL)
319  {
320  //If a set operation tries to change the value of an existing instance
321  //of this object to any value other than usmNoAuthProtocol, then an
322  //inconsistentValue error must be returned
323  if(oidComp(value->oid, valueLen, usmNoAuthProtocolOid,
324  sizeof(usmNoAuthProtocolOid)))
325  {
327  }
328 
329  //If a set operation tries to set the value to the usmNoAuthProtocol
330  //while the usmUserPrivProtocol value in the same row is not equal to
331  //usmNoPrivProtocol, then an inconsistentValue error must be returned
334 
335  //Commit phase?
336  if(commit)
337  {
338  //Once instantiated, the value of such an instance of this object
339  //can only be changed via a set operation to the value of the
340  //usmNoAuthProtocol
342  }
343  }
344  else
345  {
346  //Prepare phase?
347  if(!commit)
348  {
349  //The usmUserAuthProtocol object specifies the type of authentication
350  //protocol which is used
351  if(OID_COMP(value->oid, valueLen,
352  usmNoAuthProtocolOid) == 0)
353  {
354  //No authentication
355  }
356  else if(OID_COMP(value->oid, valueLen,
358  {
359  //HMAC-MD5-96 authentication protocol
360  }
361  else if(OID_COMP(value->oid, valueLen,
363  {
364  //HMAC-SHA-1-96 authentication protocol
365  }
366  else if(OID_COMP(value->oid, valueLen,
368  {
369  //HMAC-SHA-224-128 authentication protocol
370  }
371  else if(OID_COMP(value->oid, valueLen,
373  {
374  //HMAC-SHA-256-192 authentication protocol
375  }
376  else if(OID_COMP(value->oid, valueLen,
378  {
379  //HMAC-SHA-384-256 authentication protocol
380  }
381  else if(OID_COMP(value->oid, valueLen,
383  {
384  //HMAC-SHA-512-384 authentication protocol
385  }
386  else
387  {
388  //If an initial set operation (at row creation time) tries to
389  //set a value for an unknown or unsupported protocol, then a
390  //wrongValue error must be returned
391  return ERROR_WRONG_VALUE;
392  }
393  }
394  }
395  }
396  //usmUserAuthKeyChange or usmUserOwnAuthKeyChange object?
397  else if(osStrcmp(object->name, "usmUserAuthKeyChange") == 0 ||
398  osStrcmp(object->name, "usmUserOwnAuthKeyChange") == 0)
399  {
400  const HashAlgo *hashAlgo;
401 
402  //Unknown user name?
403  if(user == NULL)
405 
406  //usmUserOwnAuthKeyChange object?
407  if(osStrcmp(object->name, "usmUserOwnAuthKeyChange") == 0)
408  {
409  //When the user name of the requester is not the same as the umsUserName
410  //that indexes the row, then a noAccess error must be returned
411  if(osStrcmp(user->name, context->user.name) != 0)
412  return ERROR_ACCESS_DENIED;
413 
414  //When a set is received and the security model in use is not USM, then
415  //a noAccess error must be returned
416  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
417  return ERROR_ACCESS_DENIED;
418  }
419 
420  //Get the hash algorithm to be used to update the key
421  hashAlgo = snmpGetHashAlgo(user->authProtocol);
422 
423  //Invalid authentication protocol?
424  if(hashAlgo == NULL)
425  return ERROR_WRITE_FAILED;
426 
427  //The value of an instance of this object is the concatenation of
428  //two components of fixed length: first a random component and then
429  //a delta component
430  if(valueLen != (hashAlgo->digestSize * 2))
431  return ERROR_WRONG_LENGTH;
432 
433  //Commit phase?
434  if(commit)
435  {
436  //Update the localized authentication key (Kul)
437  snmpChangeKey(hashAlgo, value->octetString,
438  value->octetString + hashAlgo->digestSize, &user->localizedAuthKey);
439 
440  //The raw authentication key (Ku) is no longer valid
441  osMemset(&user->rawAuthKey, 0, sizeof(SnmpKey));
442  }
443  }
444  //usmUserPrivProtocol object?
445  else if(osStrcmp(object->name, "usmUserPrivProtocol") == 0)
446  {
447  //Check whether the user name exists
448  if(user != NULL)
449  {
450  //If a set operation tries to change the value of an existing instance
451  //of this object to any value other than usmNoPrivProtocol, then an
452  //inconsistentValue error must be returned
453  if(oidComp(value->oid, valueLen, usmNoPrivProtocolOid,
454  sizeof(usmNoPrivProtocolOid)))
455  {
457  }
458 
459  //Commit phase?
460  if(commit)
461  {
462  //Once instantiated, the value of such an instance of this object
463  //can only be changed via a set operation to the value of the
464  //usmNoPrivProtocol
466  }
467  }
468  else
469  {
470  //Prepare phase?
471  if(!commit)
472  {
473  //The usmUserPrivProtocol object specifies the type of privacy
474  //protocol which is used
475  if(OID_COMP(value->oid, valueLen, usmNoPrivProtocolOid) == 0)
476  {
477  //No privacy
478  }
479  else if(OID_COMP(value->oid, valueLen, usmDESPrivProtocolOid) == 0)
480  {
481  //DES-CBC privacy protocol
482  }
483  else if(OID_COMP(value->oid, valueLen, usmAesCfb128ProtocolOid) == 0)
484  {
485  //AES-128-CFB privacy protocol
486  }
487  else
488  {
489  //If an initial set operation (at row creation time) tries to
490  //set a value for an unknown or unsupported protocol, then a
491  //wrongValue error must be returned
492  return ERROR_WRONG_VALUE;
493  }
494  }
495  }
496  }
497  //usmUserPrivKeyChange or usmUserOwnPrivKeyChangeobject?
498  else if(osStrcmp(object->name, "usmUserPrivKeyChange") == 0 ||
499  osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
500  {
501  const HashAlgo *hashAlgo;
502 
503  //Unknown user name?
504  if(user == NULL)
506 
507  //usmUserOwnPrivKeyChange object?
508  if(osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
509  {
510  //When the user name of the requester is not the same as the umsUserName
511  //that indexes the row, then a noAccess error must be returned
512  if(osStrcmp(user->name, context->user.name) != 0)
513  return ERROR_ACCESS_DENIED;
514 
515  //When a set is received and the security model in use is not USM, then
516  //a noAccess error must be returned
517  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
518  return ERROR_ACCESS_DENIED;
519  }
520 
521  //Get the hash algorithm to be used to update the key
522  hashAlgo = snmpGetHashAlgo(user->authProtocol);
523 
524  //Invalid authentication protocol?
525  if(hashAlgo == NULL)
526  return ERROR_WRITE_FAILED;
527 
528  //The value of an instance of this object is the concatenation of
529  //two components of fixed length: first a random component and then
530  //a delta component
531  if(valueLen != (hashAlgo->digestSize * 2))
532  return ERROR_WRONG_LENGTH;
533 
534  //Commit phase?
535  if(commit)
536  {
537  //Update the localized privacy key (Kul)
538  snmpChangeKey(hashAlgo, value->octetString,
539  value->octetString + hashAlgo->digestSize, &user->localizedPrivKey);
540 
541  //The raw privacy key (Ku) is no longer valid
542  osMemset(&user->rawPrivKey, 0, sizeof(SnmpKey));
543  }
544  }
545  //usmUserPublic object?
546  else if(osStrcmp(object->name, "usmUserPublic") == 0)
547  {
548  //Check the length of the public value
549  if(valueLen > SNMP_MAX_PUBLIC_VALUE_SIZE)
550  return ERROR_WRONG_LENGTH;
551 
552  //Check whether the user name exists
553  if(user != NULL)
554  {
555  //Commit phase?
556  if(commit)
557  {
558  //The usmUserPublic can be written as part of the procedure for
559  //changing a user's secret authentication and/or privacy key,
560  //and later read to determine whether the change of the secret
561  //was effected
562  osMemcpy(user->publicValue, value->octetString, valueLen);
563 
564  //Update the length of the public value
565  user->publicValueLen = valueLen;
566  }
567  }
568  else
569  {
570  //Prepare phase?
571  if(!commit)
572  {
573  //Save the value of the public value for later use
575  valueLen);
576 
577  //Save the length of the public value
579  }
580  }
581  }
582  //usmUserStorageType object?
583  else if(osStrcmp(object->name, "usmUserStorageType") == 0)
584  {
585  //The usmUserStorageType object specifies the storage type for this
586  //conceptual row
587  if(value->integer != MIB_STORAGE_TYPE_OTHER &&
588  value->integer != MIB_STORAGE_TYPE_VOLATILE &&
589  value->integer != MIB_STORAGE_TYPE_NON_VOLATILE &&
590  value->integer != MIB_STORAGE_TYPE_PERMANENT &&
591  value->integer != MIB_STORAGE_TYPE_READ_ONLY)
592  {
593  return ERROR_WRONG_VALUE;
594  }
595  }
596  //usmUserStatus object?
597  else if(osStrcmp(object->name, "usmUserStatus") == 0)
598  {
599  MibRowStatus status;
600 
601  //Get row status
602  status = (MibRowStatus) value->integer;
603 
604  //Check the value specified by the set operation
605  if(status == MIB_ROW_STATUS_ACTIVE ||
607  {
608  //Unknown user name?
609  if(user == NULL)
611 
612  //Commit phase?
613  if(commit)
614  {
615  //The first time an instance of this object is set by a management
616  //operation, the cloning process is invoked
617  if(user->mode == SNMP_ACCESS_NONE)
618  {
619  //Valid clone-from user?
621  {
622  //Copy the security profile of the clone-from user
624  }
625  }
626 
627  //When the agent processes the set operation, it verifies that it
628  //has sufficient information to make the conceptual row available
629  //for use by the managed device
630  if(user->mode == SNMP_ACCESS_NONE)
632 
633  //Update the status of the conceptual row
634  user->status = status;
635  }
636  }
637  else if(status == MIB_ROW_STATUS_CREATE_AND_GO)
638  {
639  //User name already in use?
640  if(user != NULL)
642 
643  //Create a security profile for the new user
644  user = snmpCreateUserEntry(context);
645  //Unable to create a new user?
646  if(user == NULL)
647  return ERROR_WRITE_FAILED;
648 
649  //Commit phase?
650  if(commit)
651  {
652  //Valid clone-from user?
654  {
655  //Clear the security profile of the user
656  osMemset(user, 0, sizeof(SnmpUserEntry));
657  //Save user name
658  osStrcpy(user->name, userName);
659 
660  //Valid public value specified?
662  {
663  //Copy the public value
666 
667  //Set the length of the public value
669  }
670 
671  //Copy the security profile of the clone-from user
673 
674  //The conceptual row is now available for use by the managed device
676  }
677  else
678  {
679  //The newly created row cannot be made active
681  }
682  }
683  }
684  else if(status == MIB_ROW_STATUS_CREATE_AND_WAIT)
685  {
686  //User name already in use?
687  if(user != NULL)
689 
690  //Create a security profile for the new user
691  user = snmpCreateUserEntry(context);
692  //Unable to create a new user?
693  if(user == NULL)
694  return ERROR_WRITE_FAILED;
695 
696  //Commit phase?
697  if(commit)
698  {
699  //Clear the security profile of the user
700  osMemset(user, 0, sizeof(SnmpUserEntry));
701  //Save user name
702  osStrcpy(user->name, userName);
703 
704  //Valid public value specified?
706  {
707  //Copy the public value
710 
711  //Set the length of the public value
713  }
714 
715  //Check whether the cloning process has been invoked
716  if(user->mode != SNMP_ACCESS_NONE)
717  {
718  //Copy the security profile of the clone-from user
720 
721  //Instances of all corresponding columns are now configured
723  }
724  else
725  {
726  //Initialize columns with default values
729 
730  //Until instances of all corresponding columns are appropriately
731  //configured, the value of the corresponding instance of the
732  //usmUserStatus column is notReady
734  }
735  }
736  }
737  else if(status == MIB_ROW_STATUS_DESTROY)
738  {
739  //Check whether the user name exists
740  if(user != NULL)
741  {
742  //Commit phase?
743  if(commit)
744  {
745  //Clear the security profile of the user
746  osMemset(user, 0, sizeof(SnmpUserEntry));
747 
748  //Delete the conceptual row from the table
750  }
751  }
752  }
753  else
754  {
755  //Unsupported action
757  }
758  }
759  //Unknown object?
760  else
761  {
762  //The specified object does not exist
763  return ERROR_OBJECT_NOT_FOUND;
764  }
765 
766  //Successful processing
767  return NO_ERROR;
768 #else
769  //SET operation is not supported
770  return ERROR_WRITE_FAILED;
771 #endif
772 }
773 
774 
775 /**
776  * @brief Get usmUserEntry object value
777  * @param[in] object Pointer to the MIB object descriptor
778  * @param[in] oid Object identifier (object name and instance identifier)
779  * @param[in] oidLen Length of the OID, in bytes
780  * @param[out] value Object value
781  * @param[in,out] valueLen Length of the object value, in bytes
782  * @return Error code
783  **/
784 
785 error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid,
786  size_t oidLen, MibVariant *value, size_t *valueLen)
787 {
788  error_t error;
789  size_t n;
790  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
791  size_t userEngineIdLen;
792  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
793  SnmpAgentContext *context;
794  SnmpUserEntry *user;
795 
796  //Point to the instance identifier
797  n = object->oidLen;
798 
799  //usmUserEngineID is used as 1st instance identifier
800  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
801  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
802  //Invalid instance identifier?
803  if(error)
804  return error;
805 
806  //usmUserName is used as 2nd instance identifier
807  error = mibDecodeString(oid, oidLen, &n, userName,
809  //Invalid instance identifier?
810  if(error)
811  return error;
812 
813  //Sanity check
814  if(n != oidLen)
816 
817  //Point to the SNMP agent context
819  //Sanity check
820  if(context == NULL)
822 
823  //Check the length of the SNMP engine ID
824  if(userEngineIdLen != context->contextEngineLen)
826 
827  //Check SNMP engine ID
828  if(osMemcmp(userEngineId, context->contextEngine, userEngineIdLen))
830 
831  //Retrieve the security profile of the specified user
832  user = snmpFindUserEntry(context, userName, osStrlen(userName));
833  //Unknown user name?
834  if(user == NULL)
836 
837  //usmUserSecurityName object?
838  if(osStrcmp(object->name, "usmUserSecurityName") == 0)
839  {
840  //The security name is the same as the user name
841  n = osStrlen(user->name);
842 
843  //Make sure the buffer is large enough to hold the entire object
844  if(*valueLen >= n)
845  {
846  //Copy object value
847  osMemcpy(value->octetString, user->name, n);
848  //Return object length
849  *valueLen = n;
850  }
851  else
852  {
853  //Report an error
854  error = ERROR_BUFFER_OVERFLOW;
855  }
856  }
857  //usmUserCloneFrom object?
858  else if(osStrcmp(object->name, "usmUserCloneFrom") == 0)
859  {
860  //When this object is read, the ZeroDotZero OID is returned
861  uint8_t zeroDotZeroOid[] = {0};
862 
863  //Make sure the buffer is large enough to hold the entire object
864  if(*valueLen >= sizeof(zeroDotZeroOid))
865  {
866  //Copy object value
867  osMemcpy(value->octetString, zeroDotZeroOid, sizeof(zeroDotZeroOid));
868  //Return object length
869  *valueLen = sizeof(zeroDotZeroOid);
870  }
871  else
872  {
873  //Report an error
874  error = ERROR_BUFFER_OVERFLOW;
875  }
876  }
877  //usmUserAuthProtocol object?
878  else if(osStrcmp(object->name, "usmUserAuthProtocol") == 0)
879  {
880  size_t authProtocolLen;
881  const uint8_t *authProtocol;
882 
883  //Check the type of authentication protocol which is used
884  switch(user->authProtocol)
885  {
886  //HMAC-MD5-96 authentication protocol?
888  authProtocol = usmHMACMD5AuthProtocolOid;
889  authProtocolLen = sizeof(usmHMACMD5AuthProtocolOid);
890  break;
891  //HMAC-SHA-1-96 authentication protocol?
893  authProtocol = usmHMACSHAAuthProtocolOid;
894  authProtocolLen = sizeof(usmHMACSHAAuthProtocolOid);
895  break;
896  //HMAC-SHA-224-128 authentication protocol?
898  authProtocol = usmHMAC128SHA224AuthProtocolOid;
899  authProtocolLen = sizeof(usmHMAC128SHA224AuthProtocolOid);
900  break;
901  //HMAC-SHA-256-192 authentication protocol?
903  authProtocol = usmHMAC192SHA256AuthProtocolOid;
904  authProtocolLen = sizeof(usmHMAC192SHA256AuthProtocolOid);
905  break;
906  //HMAC-SHA-384-256 authentication protocol?
908  authProtocol = usmHMAC256SHA384AuthProtocolOid;
909  authProtocolLen = sizeof(usmHMAC256SHA384AuthProtocolOid);
910  break;
911  //HMAC-SHA-512-384 authentication protocol?
913  authProtocol = usmHMAC384SHA512AuthProtocolOid;
914  authProtocolLen = sizeof(usmHMAC384SHA512AuthProtocolOid);
915  break;
916  //No authentication?
917  default:
918  authProtocol = usmNoAuthProtocolOid;
919  authProtocolLen = sizeof(usmNoAuthProtocolOid);
920  break;
921  }
922 
923  //Make sure the buffer is large enough to hold the entire object
924  if(*valueLen >= authProtocolLen)
925  {
926  //Copy object value
927  osMemcpy(value->octetString, authProtocol, authProtocolLen);
928  //Return object length
929  *valueLen = authProtocolLen;
930  }
931  else
932  {
933  //Report an error
934  error = ERROR_BUFFER_OVERFLOW;
935  }
936  }
937  //usmUserAuthKeyChange object?
938  else if(osStrcmp(object->name, "usmUserAuthKeyChange") == 0)
939  {
940  //When this object is read, the zero-length (empty) string is returned
941  *valueLen = 0;
942  }
943  //usmUserOwnAuthKeyChange object?
944  else if(osStrcmp(object->name, "usmUserOwnAuthKeyChange") == 0)
945  {
946  //When this object is read, the zero-length (empty) string is returned
947  *valueLen = 0;
948  }
949  //usmUserPrivProtocol object?
950  else if(osStrcmp(object->name, "usmUserPrivProtocol") == 0)
951  {
952  size_t privProtocolLen;
953  const uint8_t *privProtocol;
954 
955  //Check the type of privacy protocol which is used
956  switch(user->privProtocol)
957  {
958  //DES-CBC privacy protocol?
960  privProtocol = usmDESPrivProtocolOid;
961  privProtocolLen = sizeof(usmDESPrivProtocolOid);
962  break;
963  //AES-128-CFB privacy protocol?
965  privProtocol = usmAesCfb128ProtocolOid;
966  privProtocolLen = sizeof(usmAesCfb128ProtocolOid);
967  break;
968  //No privacy?
969  default:
970  privProtocol = usmNoPrivProtocolOid;
971  privProtocolLen = sizeof(usmNoPrivProtocolOid);
972  break;
973  }
974 
975  //Make sure the buffer is large enough to hold the entire object
976  if(*valueLen >= privProtocolLen)
977  {
978  //Copy object value
979  osMemcpy(value->octetString, privProtocol, privProtocolLen);
980  //Return object length
981  *valueLen = privProtocolLen;
982  }
983  else
984  {
985  //Report an error
986  error = ERROR_BUFFER_OVERFLOW;
987  }
988  }
989  //usmUserPrivKeyChange object?
990  else if(osStrcmp(object->name, "usmUserPrivKeyChange") == 0)
991  {
992  //When this object is read, the zero-length (empty) string is returned
993  *valueLen = 0;
994  }
995  //usmUserOwnPrivKeyChange object?
996  else if(osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
997  {
998  //When this object is read, the zero-length (empty) string is returned
999  *valueLen = 0;
1000  }
1001  //usmUserPublic object?
1002  else if(osStrcmp(object->name, "usmUserPublic") == 0)
1003  {
1004  //Make sure the buffer is large enough to hold the public value
1005  if(*valueLen >= user->publicValueLen)
1006  {
1007  //The public value can be read to determine whether the change of
1008  //the secret was effected
1009  osMemcpy(value->octetString, user->publicValue, user->publicValueLen);
1010 
1011  //Return object length
1012  *valueLen = user->publicValueLen;
1013  }
1014  else
1015  {
1016  //Report an error
1017  error = ERROR_BUFFER_OVERFLOW;
1018  }
1019  }
1020  //usmUserStorageType object?
1021  else if(osStrcmp(object->name, "usmUserStorageType") == 0)
1022  {
1023  //Get the storage type for this conceptual row
1024  value->integer = MIB_STORAGE_TYPE_VOLATILE;
1025  }
1026  //usmUserStatus object?
1027  else if(osStrcmp(object->name, "usmUserStatus") == 0)
1028  {
1029  //Get the status of this conceptual row
1030  value->integer = user->status;
1031  }
1032  //Unknown object?
1033  else
1034  {
1035  //The specified object does not exist
1036  error = ERROR_OBJECT_NOT_FOUND;
1037  }
1038 
1039  //Return status code
1040  return error;
1041 }
1042 
1043 
1044 /**
1045  * @brief Get next usmUserEntry object
1046  * @param[in] object Pointer to the MIB object descriptor
1047  * @param[in] oid Object identifier
1048  * @param[in] oidLen Length of the OID, in bytes
1049  * @param[out] nextOid OID of the next object in the MIB
1050  * @param[out] nextOidLen Length of the next object identifier, in bytes
1051  * @return Error code
1052  **/
1053 
1054 error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid,
1055  size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
1056 {
1057  error_t error;
1058  uint_t i;
1059  size_t n;
1060  bool_t acceptable;
1061  SnmpAgentContext *context;
1062  SnmpUserEntry *entry;
1063  SnmpUserEntry *nextEntry;
1064 
1065  //Initialize variables
1066  nextEntry = NULL;
1067 
1068  //Point to the SNMP agent context
1069  context = (SnmpAgentContext *) snmpUsmMibBase.context;
1070  //Sanity check
1071  if(context == NULL)
1072  return ERROR_OBJECT_NOT_FOUND;
1073 
1074  //Make sure the buffer is large enough to hold the OID prefix
1075  if(*nextOidLen < object->oidLen)
1076  return ERROR_BUFFER_OVERFLOW;
1077 
1078  //Copy OID prefix
1079  osMemcpy(nextOid, object->oid, object->oidLen);
1080 
1081  //Loop through the list of users
1082  for(i = 0; i < SNMP_AGENT_MAX_USERS; i++)
1083  {
1084  //Point to the current entry
1085  entry = &context->userTable[i];
1086 
1087  //Check the status of the row
1088  if(entry->status != MIB_ROW_STATUS_UNUSED)
1089  {
1090  //Append the instance identifier to the OID prefix
1091  n = object->oidLen;
1092 
1093  //usmUserEngineID is used as 1st instance identifier
1094  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1095  context->contextEngine, context->contextEngineLen, FALSE);
1096  //Any error to report?
1097  if(error)
1098  return error;
1099 
1100  //usmUserName is used as 2nd instance identifier
1101  error = mibEncodeString(nextOid, *nextOidLen, &n, entry->name, FALSE);
1102  //Any error to report?
1103  if(error)
1104  return error;
1105 
1106  //Check whether the resulting object identifier lexicographically
1107  //follows the specified OID
1108  if(oidComp(nextOid, n, oid, oidLen) > 0)
1109  {
1110  //Perform lexicographic comparison
1111  if(nextEntry == NULL)
1112  {
1113  acceptable = TRUE;
1114  }
1115  else if(osStrlen(entry->name) < osStrlen(nextEntry->name))
1116  {
1117  acceptable = TRUE;
1118  }
1119  else if(osStrlen(entry->name) > osStrlen(nextEntry->name))
1120  {
1121  acceptable = FALSE;
1122  }
1123  else if(osStrcmp(entry->name, nextEntry->name) < 0)
1124  {
1125  acceptable = TRUE;
1126  }
1127  else
1128  {
1129  acceptable = FALSE;
1130  }
1131 
1132  //Save the closest object identifier that follows the specified
1133  //OID in lexicographic order
1134  if(acceptable)
1135  nextEntry = entry;
1136  }
1137  }
1138  }
1139 
1140  //The specified OID does not lexicographically precede the name
1141  //of some object?
1142  if(nextEntry == NULL)
1143  return ERROR_OBJECT_NOT_FOUND;
1144 
1145  //Append the instance identifier to the OID prefix
1146  n = object->oidLen;
1147 
1148  //usmUserEngineID is used as 1st instance identifier
1149  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1150  context->contextEngine, context->contextEngineLen, FALSE);
1151  //Any error to report?
1152  if(error)
1153  return error;
1154 
1155  //usmUserName is used as 2nd instance identifier
1156  error = mibEncodeString(nextOid, *nextOidLen, &n, nextEntry->name, FALSE);
1157  //Any error to report?
1158  if(error)
1159  return error;
1160 
1161  //Save the length of the resulting object identifier
1162  *nextOidLen = n;
1163  //Next object found
1164  return NO_ERROR;
1165 }
1166 
1167 #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.
int bool_t
Definition: compiler_port.h:61
uint32_t netGetRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net.c:417
@ 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)
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:1088
@ 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.
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:1082
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