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-2024 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.4.4
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(!oidComp(value->oid, valueLen, usmNoAuthProtocolOid,
352  sizeof(usmNoAuthProtocolOid)))
353  {
354  //No authentication
355  }
356  else if(!oidComp(value->oid, valueLen, usmHMACMD5AuthProtocolOid,
357  sizeof(usmHMACMD5AuthProtocolOid)))
358  {
359  //HMAC-MD5-96 authentication protocol
360  }
361  else if(!oidComp(value->oid, valueLen, usmHMACSHAAuthProtocolOid,
362  sizeof(usmHMACSHAAuthProtocolOid)))
363  {
364  //HMAC-SHA-1-96 authentication protocol
365  }
366  else if(!oidComp(value->oid, valueLen, usmHMAC128SHA224AuthProtocolOid,
368  {
369  //HMAC-SHA-224-128 authentication protocol
370  }
371  else if(!oidComp(value->oid, valueLen, usmHMAC192SHA256AuthProtocolOid,
373  {
374  //HMAC-SHA-256-192 authentication protocol
375  }
376  else if(!oidComp(value->oid, valueLen, usmHMAC256SHA384AuthProtocolOid,
378  {
379  //HMAC-SHA-384-256 authentication protocol
380  }
381  else if(!oidComp(value->oid, valueLen, usmHMAC384SHA512AuthProtocolOid,
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(!oidComp(value->oid, valueLen, usmNoPrivProtocolOid,
476  sizeof(usmNoPrivProtocolOid)))
477  {
478  //No privacy
479  }
480  else if(!oidComp(value->oid, valueLen, usmDESPrivProtocolOid,
481  sizeof(usmDESPrivProtocolOid)))
482  {
483  //DES-CBC privacy protocol
484  }
485  else if(!oidComp(value->oid, valueLen, usmAesCfb128ProtocolOid,
486  sizeof(usmAesCfb128ProtocolOid)))
487  {
488  //AES-128-CFB privacy protocol
489  }
490  else
491  {
492  //If an initial set operation (at row creation time) tries to
493  //set a value for an unknown or unsupported protocol, then a
494  //wrongValue error must be returned
495  return ERROR_WRONG_VALUE;
496  }
497  }
498  }
499  }
500  //usmUserPrivKeyChange or usmUserOwnPrivKeyChangeobject?
501  else if(osStrcmp(object->name, "usmUserPrivKeyChange") == 0 ||
502  osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
503  {
504  const HashAlgo *hashAlgo;
505 
506  //Unknown user name?
507  if(user == NULL)
509 
510  //usmUserOwnPrivKeyChange object?
511  if(osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
512  {
513  //When the user name of the requester is not the same as the umsUserName
514  //that indexes the row, then a noAccess error must be returned
515  if(osStrcmp(user->name, context->user.name) != 0)
516  return ERROR_ACCESS_DENIED;
517 
518  //When a set is received and the security model in use is not USM, then
519  //a noAccess error must be returned
520  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
521  return ERROR_ACCESS_DENIED;
522  }
523 
524  //Get the hash algorithm to be used to update the key
525  hashAlgo = snmpGetHashAlgo(user->authProtocol);
526 
527  //Invalid authentication protocol?
528  if(hashAlgo == NULL)
529  return ERROR_WRITE_FAILED;
530 
531  //The value of an instance of this object is the concatenation of
532  //two components of fixed length: first a random component and then
533  //a delta component
534  if(valueLen != (hashAlgo->digestSize * 2))
535  return ERROR_WRONG_LENGTH;
536 
537  //Commit phase?
538  if(commit)
539  {
540  //Update the localized privacy key (Kul)
541  snmpChangeKey(hashAlgo, value->octetString,
542  value->octetString + hashAlgo->digestSize, &user->localizedPrivKey);
543 
544  //The raw privacy key (Ku) is no longer valid
545  osMemset(&user->rawPrivKey, 0, sizeof(SnmpKey));
546  }
547  }
548  //usmUserPublic object?
549  else if(osStrcmp(object->name, "usmUserPublic") == 0)
550  {
551  //Check the length of the public value
552  if(valueLen > SNMP_MAX_PUBLIC_VALUE_SIZE)
553  return ERROR_WRONG_LENGTH;
554 
555  //Check whether the user name exists
556  if(user != NULL)
557  {
558  //Commit phase?
559  if(commit)
560  {
561  //The usmUserPublic can be written as part of the procedure for
562  //changing a user's secret authentication and/or privacy key,
563  //and later read to determine whether the change of the secret
564  //was effected
565  osMemcpy(user->publicValue, value->octetString, valueLen);
566 
567  //Update the length of the public value
568  user->publicValueLen = valueLen;
569  }
570  }
571  else
572  {
573  //Prepare phase?
574  if(!commit)
575  {
576  //Save the value of the public value for later use
578  valueLen);
579 
580  //Save the length of the public value
582  }
583  }
584  }
585  //usmUserStorageType object?
586  else if(osStrcmp(object->name, "usmUserStorageType") == 0)
587  {
588  //The usmUserStorageType object specifies the storage type for this
589  //conceptual row
590  if(value->integer != MIB_STORAGE_TYPE_OTHER &&
591  value->integer != MIB_STORAGE_TYPE_VOLATILE &&
592  value->integer != MIB_STORAGE_TYPE_NON_VOLATILE &&
593  value->integer != MIB_STORAGE_TYPE_PERMANENT &&
594  value->integer != MIB_STORAGE_TYPE_READ_ONLY)
595  {
596  return ERROR_WRONG_VALUE;
597  }
598  }
599  //usmUserStatus object?
600  else if(osStrcmp(object->name, "usmUserStatus") == 0)
601  {
602  MibRowStatus status;
603 
604  //Get row status
605  status = (MibRowStatus) value->integer;
606 
607  //Check the value specified by the set operation
608  if(status == MIB_ROW_STATUS_ACTIVE ||
610  {
611  //Unknown user name?
612  if(user == NULL)
614 
615  //Commit phase?
616  if(commit)
617  {
618  //The first time an instance of this object is set by a management
619  //operation, the cloning process is invoked
620  if(user->mode == SNMP_ACCESS_NONE)
621  {
622  //Valid clone-from user?
624  {
625  //Copy the security profile of the clone-from user
627  }
628  }
629 
630  //When the agent processes the set operation, it verifies that it
631  //has sufficient information to make the conceptual row available
632  //for use by the managed device
633  if(user->mode == SNMP_ACCESS_NONE)
635 
636  //Update the status of the conceptual row
637  user->status = status;
638  }
639  }
640  else if(status == MIB_ROW_STATUS_CREATE_AND_GO)
641  {
642  //User name already in use?
643  if(user != NULL)
645 
646  //Create a security profile for the new user
647  user = snmpCreateUserEntry(context);
648  //Unable to create a new user?
649  if(user == NULL)
650  return ERROR_WRITE_FAILED;
651 
652  //Commit phase?
653  if(commit)
654  {
655  //Valid clone-from user?
657  {
658  //Clear the security profile of the user
659  osMemset(user, 0, sizeof(SnmpUserEntry));
660  //Save user name
661  osStrcpy(user->name, userName);
662 
663  //Valid public value specified?
665  {
666  //Copy the public value
669 
670  //Set the length of the public value
672  }
673 
674  //Copy the security profile of the clone-from user
676 
677  //The conceptual row is now available for use by the managed device
679  }
680  else
681  {
682  //The newly created row cannot be made active
684  }
685  }
686  }
687  else if(status == MIB_ROW_STATUS_CREATE_AND_WAIT)
688  {
689  //User name already in use?
690  if(user != NULL)
692 
693  //Create a security profile for the new user
694  user = snmpCreateUserEntry(context);
695  //Unable to create a new user?
696  if(user == NULL)
697  return ERROR_WRITE_FAILED;
698 
699  //Commit phase?
700  if(commit)
701  {
702  //Clear the security profile of the user
703  osMemset(user, 0, sizeof(SnmpUserEntry));
704  //Save user name
705  osStrcpy(user->name, userName);
706 
707  //Valid public value specified?
709  {
710  //Copy the public value
713 
714  //Set the length of the public value
716  }
717 
718  //Check whether the cloning process has been invoked
719  if(user->mode != SNMP_ACCESS_NONE)
720  {
721  //Copy the security profile of the clone-from user
723 
724  //Instances of all corresponding columns are now configured
726  }
727  else
728  {
729  //Initialize columns with default values
732 
733  //Until instances of all corresponding columns are appropriately
734  //configured, the value of the corresponding instance of the
735  //usmUserStatus column is notReady
737  }
738  }
739  }
740  else if(status == MIB_ROW_STATUS_DESTROY)
741  {
742  //Check whether the user name exists
743  if(user != NULL)
744  {
745  //Commit phase?
746  if(commit)
747  {
748  //Clear the security profile of the user
749  osMemset(user, 0, sizeof(SnmpUserEntry));
750 
751  //Delete the conceptual row from the table
753  }
754  }
755  }
756  else
757  {
758  //Unsupported action
760  }
761  }
762  //Unknown object?
763  else
764  {
765  //The specified object does not exist
766  return ERROR_OBJECT_NOT_FOUND;
767  }
768 
769  //Successful processing
770  return NO_ERROR;
771 #else
772  //SET operation is not supported
773  return ERROR_WRITE_FAILED;
774 #endif
775 }
776 
777 
778 /**
779  * @brief Get usmUserEntry object value
780  * @param[in] object Pointer to the MIB object descriptor
781  * @param[in] oid Object identifier (object name and instance identifier)
782  * @param[in] oidLen Length of the OID, in bytes
783  * @param[out] value Object value
784  * @param[in,out] valueLen Length of the object value, in bytes
785  * @return Error code
786  **/
787 
788 error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid,
789  size_t oidLen, MibVariant *value, size_t *valueLen)
790 {
791  error_t error;
792  size_t n;
793  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
794  size_t userEngineIdLen;
795  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
796  SnmpAgentContext *context;
797  SnmpUserEntry *user;
798 
799  //Point to the instance identifier
800  n = object->oidLen;
801 
802  //usmUserEngineID is used as 1st instance identifier
803  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
804  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
805  //Invalid instance identifier?
806  if(error)
807  return error;
808 
809  //usmUserName is used as 2nd instance identifier
810  error = mibDecodeString(oid, oidLen, &n, userName,
812  //Invalid instance identifier?
813  if(error)
814  return error;
815 
816  //Sanity check
817  if(n != oidLen)
819 
820  //Point to the SNMP agent context
822  //Sanity check
823  if(context == NULL)
825 
826  //Check the length of the SNMP engine ID
827  if(userEngineIdLen != context->contextEngineLen)
829 
830  //Check SNMP engine ID
831  if(osMemcmp(userEngineId, context->contextEngine, userEngineIdLen))
833 
834  //Retrieve the security profile of the specified user
835  user = snmpFindUserEntry(context, userName, osStrlen(userName));
836  //Unknown user name?
837  if(user == NULL)
839 
840  //usmUserSecurityName object?
841  if(osStrcmp(object->name, "usmUserSecurityName") == 0)
842  {
843  //The security name is the same as the user name
844  n = osStrlen(user->name);
845 
846  //Make sure the buffer is large enough to hold the entire object
847  if(*valueLen >= n)
848  {
849  //Copy object value
850  osMemcpy(value->octetString, user->name, n);
851  //Return object length
852  *valueLen = n;
853  }
854  else
855  {
856  //Report an error
857  error = ERROR_BUFFER_OVERFLOW;
858  }
859  }
860  //usmUserCloneFrom object?
861  else if(osStrcmp(object->name, "usmUserCloneFrom") == 0)
862  {
863  //When this object is read, the ZeroDotZero OID is returned
864  uint8_t zeroDotZeroOid[] = {0};
865 
866  //Make sure the buffer is large enough to hold the entire object
867  if(*valueLen >= sizeof(zeroDotZeroOid))
868  {
869  //Copy object value
870  osMemcpy(value->octetString, zeroDotZeroOid, sizeof(zeroDotZeroOid));
871  //Return object length
872  *valueLen = sizeof(zeroDotZeroOid);
873  }
874  else
875  {
876  //Report an error
877  error = ERROR_BUFFER_OVERFLOW;
878  }
879  }
880  //usmUserAuthProtocol object?
881  else if(osStrcmp(object->name, "usmUserAuthProtocol") == 0)
882  {
883  size_t authProtocolLen;
884  const uint8_t *authProtocol;
885 
886  //Check the type of authentication protocol which is used
887  switch(user->authProtocol)
888  {
889  //HMAC-MD5-96 authentication protocol?
891  authProtocol = usmHMACMD5AuthProtocolOid;
892  authProtocolLen = sizeof(usmHMACMD5AuthProtocolOid);
893  break;
894  //HMAC-SHA-1-96 authentication protocol?
896  authProtocol = usmHMACSHAAuthProtocolOid;
897  authProtocolLen = sizeof(usmHMACSHAAuthProtocolOid);
898  break;
899  //HMAC-SHA-224-128 authentication protocol?
901  authProtocol = usmHMAC128SHA224AuthProtocolOid;
902  authProtocolLen = sizeof(usmHMAC128SHA224AuthProtocolOid);
903  break;
904  //HMAC-SHA-256-192 authentication protocol?
906  authProtocol = usmHMAC192SHA256AuthProtocolOid;
907  authProtocolLen = sizeof(usmHMAC192SHA256AuthProtocolOid);
908  break;
909  //HMAC-SHA-384-256 authentication protocol?
911  authProtocol = usmHMAC256SHA384AuthProtocolOid;
912  authProtocolLen = sizeof(usmHMAC256SHA384AuthProtocolOid);
913  break;
914  //HMAC-SHA-512-384 authentication protocol?
916  authProtocol = usmHMAC384SHA512AuthProtocolOid;
917  authProtocolLen = sizeof(usmHMAC384SHA512AuthProtocolOid);
918  break;
919  //No authentication?
920  default:
921  authProtocol = usmNoAuthProtocolOid;
922  authProtocolLen = sizeof(usmNoAuthProtocolOid);
923  break;
924  }
925 
926  //Make sure the buffer is large enough to hold the entire object
927  if(*valueLen >= authProtocolLen)
928  {
929  //Copy object value
930  osMemcpy(value->octetString, authProtocol, authProtocolLen);
931  //Return object length
932  *valueLen = authProtocolLen;
933  }
934  else
935  {
936  //Report an error
937  error = ERROR_BUFFER_OVERFLOW;
938  }
939  }
940  //usmUserAuthKeyChange object?
941  else if(osStrcmp(object->name, "usmUserAuthKeyChange") == 0)
942  {
943  //When this object is read, the zero-length (empty) string is returned
944  *valueLen = 0;
945  }
946  //usmUserOwnAuthKeyChange object?
947  else if(osStrcmp(object->name, "usmUserOwnAuthKeyChange") == 0)
948  {
949  //When this object is read, the zero-length (empty) string is returned
950  *valueLen = 0;
951  }
952  //usmUserPrivProtocol object?
953  else if(osStrcmp(object->name, "usmUserPrivProtocol") == 0)
954  {
955  size_t privProtocolLen;
956  const uint8_t *privProtocol;
957 
958  //Check the type of privacy protocol which is used
959  switch(user->privProtocol)
960  {
961  //DES-CBC privacy protocol?
963  privProtocol = usmDESPrivProtocolOid;
964  privProtocolLen = sizeof(usmDESPrivProtocolOid);
965  break;
966  //AES-128-CFB privacy protocol?
968  privProtocol = usmAesCfb128ProtocolOid;
969  privProtocolLen = sizeof(usmAesCfb128ProtocolOid);
970  break;
971  //No privacy?
972  default:
973  privProtocol = usmNoPrivProtocolOid;
974  privProtocolLen = sizeof(usmNoPrivProtocolOid);
975  break;
976  }
977 
978  //Make sure the buffer is large enough to hold the entire object
979  if(*valueLen >= privProtocolLen)
980  {
981  //Copy object value
982  osMemcpy(value->octetString, privProtocol, privProtocolLen);
983  //Return object length
984  *valueLen = privProtocolLen;
985  }
986  else
987  {
988  //Report an error
989  error = ERROR_BUFFER_OVERFLOW;
990  }
991  }
992  //usmUserPrivKeyChange object?
993  else if(osStrcmp(object->name, "usmUserPrivKeyChange") == 0)
994  {
995  //When this object is read, the zero-length (empty) string is returned
996  *valueLen = 0;
997  }
998  //usmUserOwnPrivKeyChange object?
999  else if(osStrcmp(object->name, "usmUserOwnPrivKeyChange") == 0)
1000  {
1001  //When this object is read, the zero-length (empty) string is returned
1002  *valueLen = 0;
1003  }
1004  //usmUserPublic object?
1005  else if(osStrcmp(object->name, "usmUserPublic") == 0)
1006  {
1007  //Make sure the buffer is large enough to hold the public value
1008  if(*valueLen >= user->publicValueLen)
1009  {
1010  //The public value can be read to determine whether the change of
1011  //the secret was effected
1012  osMemcpy(value->octetString, user->publicValue, user->publicValueLen);
1013 
1014  //Return object length
1015  *valueLen = user->publicValueLen;
1016  }
1017  else
1018  {
1019  //Report an error
1020  error = ERROR_BUFFER_OVERFLOW;
1021  }
1022  }
1023  //usmUserStorageType object?
1024  else if(osStrcmp(object->name, "usmUserStorageType") == 0)
1025  {
1026  //Get the storage type for this conceptual row
1027  value->integer = MIB_STORAGE_TYPE_VOLATILE;
1028  }
1029  //usmUserStatus object?
1030  else if(osStrcmp(object->name, "usmUserStatus") == 0)
1031  {
1032  //Get the status of this conceptual row
1033  value->integer = user->status;
1034  }
1035  //Unknown object?
1036  else
1037  {
1038  //The specified object does not exist
1039  error = ERROR_OBJECT_NOT_FOUND;
1040  }
1041 
1042  //Return status code
1043  return error;
1044 }
1045 
1046 
1047 /**
1048  * @brief Get next usmUserEntry object
1049  * @param[in] object Pointer to the MIB object descriptor
1050  * @param[in] oid Object identifier
1051  * @param[in] oidLen Length of the OID, in bytes
1052  * @param[out] nextOid OID of the next object in the MIB
1053  * @param[out] nextOidLen Length of the next object identifier, in bytes
1054  * @return Error code
1055  **/
1056 
1057 error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid,
1058  size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
1059 {
1060  error_t error;
1061  uint_t i;
1062  size_t n;
1063  bool_t acceptable;
1064  SnmpAgentContext *context;
1065  SnmpUserEntry *entry;
1066  SnmpUserEntry *nextEntry;
1067 
1068  //Initialize variables
1069  nextEntry = NULL;
1070 
1071  //Point to the SNMP agent context
1072  context = (SnmpAgentContext *) snmpUsmMibBase.context;
1073  //Sanity check
1074  if(context == NULL)
1075  return ERROR_OBJECT_NOT_FOUND;
1076 
1077  //Make sure the buffer is large enough to hold the OID prefix
1078  if(*nextOidLen < object->oidLen)
1079  return ERROR_BUFFER_OVERFLOW;
1080 
1081  //Copy OID prefix
1082  osMemcpy(nextOid, object->oid, object->oidLen);
1083 
1084  //Loop through the list of users
1085  for(i = 0; i < SNMP_AGENT_MAX_USERS; i++)
1086  {
1087  //Point to the current entry
1088  entry = &context->userTable[i];
1089 
1090  //Check the status of the row
1091  if(entry->status != MIB_ROW_STATUS_UNUSED)
1092  {
1093  //Append the instance identifier to the OID prefix
1094  n = object->oidLen;
1095 
1096  //usmUserEngineID is used as 1st instance identifier
1097  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1098  context->contextEngine, context->contextEngineLen, FALSE);
1099  //Any error to report?
1100  if(error)
1101  return error;
1102 
1103  //usmUserName is used as 2nd instance identifier
1104  error = mibEncodeString(nextOid, *nextOidLen, &n, entry->name, FALSE);
1105  //Any error to report?
1106  if(error)
1107  return error;
1108 
1109  //Check whether the resulting object identifier lexicographically
1110  //follows the specified OID
1111  if(oidComp(nextOid, n, oid, oidLen) > 0)
1112  {
1113  //Perform lexicographic comparison
1114  if(nextEntry == NULL)
1115  {
1116  acceptable = TRUE;
1117  }
1118  else if(osStrlen(entry->name) < osStrlen(nextEntry->name))
1119  {
1120  acceptable = TRUE;
1121  }
1122  else if(osStrlen(entry->name) > osStrlen(nextEntry->name))
1123  {
1124  acceptable = FALSE;
1125  }
1126  else if(osStrcmp(entry->name, nextEntry->name) < 0)
1127  {
1128  acceptable = TRUE;
1129  }
1130  else
1131  {
1132  acceptable = FALSE;
1133  }
1134 
1135  //Save the closest object identifier that follows the specified
1136  //OID in lexicographic order
1137  if(acceptable)
1138  nextEntry = entry;
1139  }
1140  }
1141  }
1142 
1143  //The specified OID does not lexicographically precede the name
1144  //of some object?
1145  if(nextEntry == NULL)
1146  return ERROR_OBJECT_NOT_FOUND;
1147 
1148  //Append the instance identifier to the OID prefix
1149  n = object->oidLen;
1150 
1151  //usmUserEngineID is used as 1st instance identifier
1152  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1153  context->contextEngine, context->contextEngineLen, FALSE);
1154  //Any error to report?
1155  if(error)
1156  return error;
1157 
1158  //usmUserName is used as 2nd instance identifier
1159  error = mibEncodeString(nextOid, *nextOidLen, &n, nextEntry->name, FALSE);
1160  //Any error to report?
1161  if(error)
1162  return error;
1163 
1164  //Save the length of the resulting object identifier
1165  *nextOidLen = n;
1166  //Next object found
1167  return NO_ERROR;
1168 }
1169 
1170 #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:53
uint32_t netGetRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net.c:413
@ 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:142
@ 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:1052
@ SNMP_AUTH_PROTOCOL_SHA384
HMAC-SHA-384-256.
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
@ SNMP_SECURITY_MODEL_USM
User-based security model.
#define osStrcmp(s1, s2)
Definition: os_port.h:171
#define osStrlen(s)
Definition: os_port.h:165
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:141
@ SNMP_PRIV_PROTOCOL_NONE
No privacy.
error_t
Error codes.
Definition: error.h:43
@ ERROR_INSTANCE_NOT_FOUND
Definition: error.h:257
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:148
const uint8_t usmHMAC256SHA384AuthProtocolOid[9]
@ ERROR_WRONG_LENGTH
Definition: error.h:120
#define TRACE_INFO(...)
Definition: debug.h:95
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:48
@ 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.
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:222
@ ERROR_OBJECT_NOT_FOUND
Definition: error.h:256
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:369
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:1046
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:50
SnmpAgentContext * context
#define osMemset(p, value, length)
Definition: os_port.h:135
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:207
@ 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