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.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"))
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"))
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") ||
398  !osStrcmp(object->name, "usmUserOwnAuthKeyChange"))
399  {
400  const HashAlgo *hashAlgo;
401 
402  //Unknown user name?
403  if(user == NULL)
405 
406  //usmUserOwnAuthKeyChange object?
407  if(!osStrcmp(object->name, "usmUserOwnAuthKeyChange"))
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))
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"))
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") ||
502  !osStrcmp(object->name, "usmUserOwnPrivKeyChange"))
503  {
504  const HashAlgo *hashAlgo;
505 
506  //Unknown user name?
507  if(user == NULL)
509 
510  //usmUserOwnPrivKeyChange object?
511  if(!osStrcmp(object->name, "usmUserOwnPrivKeyChange"))
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))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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"))
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
ASN.1 (Abstract Syntax Notation One)
unsigned int uint_t
Definition: compiler_port.h:50
char char_t
Definition: compiler_port.h:48
int bool_t
Definition: compiler_port.h:53
General definitions for cryptographic algorithms.
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_WRONG_LENGTH
Definition: error.h:120
@ ERROR_WRITE_FAILED
Definition: error.h:221
@ ERROR_OBJECT_NOT_FOUND
Definition: error.h:255
@ ERROR_INSTANCE_NOT_FOUND
Definition: error.h:256
@ ERROR_WRONG_VALUE
Definition: error.h:123
@ ERROR_ACCESS_DENIED
Definition: error.h:148
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
@ ERROR_INCONSISTENT_VALUE
Definition: error.h:124
uint8_t oid[]
Definition: lldp_tlv.h:300
uint8_t oidLen
Definition: lldp_tlv.h:299
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
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
error_t mibTestAndIncSpinLock(int32_t *spinLock, int32_t value, bool_t commit)
Test and increment spin lock.
Definition: mib_common.c:1006
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
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
Common definitions for MIB modules.
#define MibObject
Definition: mib_common.h:46
MibRowStatus
Row status.
Definition: mib_common.h:101
@ MIB_ROW_STATUS_CREATE_AND_WAIT
Definition: mib_common.h:107
@ MIB_ROW_STATUS_UNUSED
Definition: mib_common.h:102
@ MIB_ROW_STATUS_ACTIVE
Definition: mib_common.h:103
@ MIB_ROW_STATUS_NOT_IN_SERVICE
Definition: mib_common.h:104
@ MIB_ROW_STATUS_DESTROY
Definition: mib_common.h:108
@ MIB_ROW_STATUS_CREATE_AND_GO
Definition: mib_common.h:106
@ MIB_ROW_STATUS_NOT_READY
Definition: mib_common.h:105
@ MIB_STORAGE_TYPE_NON_VOLATILE
Definition: mib_common.h:120
@ MIB_STORAGE_TYPE_OTHER
Definition: mib_common.h:118
@ MIB_STORAGE_TYPE_READ_ONLY
Definition: mib_common.h:122
@ MIB_STORAGE_TYPE_PERMANENT
Definition: mib_common.h:121
@ MIB_STORAGE_TYPE_VOLATILE
Definition: mib_common.h:119
MibVariant
Definition: mib_common.h:196
uint32_t netGetRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net.c:416
TCP/IP stack core.
int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2, size_t oidLen2)
Compare object identifiers.
Definition: oid.c:103
OID (Object Identifier)
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osStrcmp(s1, s2)
Definition: os_port.h:171
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
#define osStrlen(s)
Definition: os_port.h:165
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define osStrcpy(s1, s2)
Definition: os_port.h:207
SNMP agent (Simple Network Management Protocol)
#define SnmpAgentContext
Definition: snmp_agent.h:36
#define SNMP_AGENT_MAX_USERS
Definition: snmp_agent.h:83
void snmpChangeKey(const HashAlgo *hashAlgo, const uint8_t *random, const uint8_t *delta, SnmpKey *key)
Change secret key.
void snmpCloneSecurityParameters(SnmpUserEntry *user, const SnmpUserEntry *cloneFromUser)
Clone security parameters.
SnmpUserEntry * snmpCreateUserEntry(SnmpAgentContext *context)
Create a new user entry.
const HashAlgo * snmpGetHashAlgo(SnmpAuthProtocol authProtocol)
Get the hash algorithm to be used for a given authentication protocol.
SnmpUserEntry * snmpFindUserEntry(SnmpAgentContext *context, const char_t *name, size_t length)
Search the user table for a given user name.
@ SNMP_AUTH_PROTOCOL_SHA512
HMAC-SHA-512-384.
@ SNMP_AUTH_PROTOCOL_NONE
No authentication.
@ SNMP_AUTH_PROTOCOL_SHA224
HMAC-SHA-224-128.
@ SNMP_AUTH_PROTOCOL_MD5
HMAC-MD5-96.
@ SNMP_AUTH_PROTOCOL_SHA384
HMAC-SHA-384-256.
@ SNMP_AUTH_PROTOCOL_SHA1
HMAC-SHA-1-96.
@ SNMP_AUTH_PROTOCOL_SHA256
HMAC-SHA-256-192.
@ SNMP_ACCESS_NONE
@ SNMP_SECURITY_MODEL_USM
User-based security model.
@ SNMP_PRIV_PROTOCOL_DES
DES-CBC.
@ SNMP_PRIV_PROTOCOL_NONE
No privacy.
@ SNMP_PRIV_PROTOCOL_AES
AES-128-CFB.
#define SNMP_MAX_CONTEXT_ENGINE_SIZE
Definition: snmp_common.h:67
#define SNMP_MAX_PUBLIC_VALUE_SIZE
Definition: snmp_common.h:88
#define SNMP_MAX_USER_NAME_LEN
Definition: snmp_common.h:81
const uint8_t usmDESPrivProtocolOid[9]
const uint8_t usmNoPrivProtocolOid[9]
const uint8_t usmHMAC256SHA384AuthProtocolOid[9]
void snmpUsmMibUnload(void *context)
Unload SNMP USM MIB module.
error_t snmpUsmMibLoad(void *context)
Load SNMP USM MIB module.
void snmpUsmMibLock(void)
Lock SNMP USM MIB base.
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.
void snmpUsmMibUnlock(void)
Unlock SNMP USM MIB base.
error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen)
Get usmUserEntry object value.
error_t snmpUsmMibInit(void)
SNMP USM MIB module initialization.
const uint8_t usmUserEntryOid[10]
const uint8_t usmHMAC192SHA256AuthProtocolOid[9]
const uint8_t usmHMAC384SHA512AuthProtocolOid[9]
const uint8_t usmAesCfb128ProtocolOid[9]
const uint8_t usmHMACSHAAuthProtocolOid[9]
const uint8_t usmHMACMD5AuthProtocolOid[9]
const uint8_t usmHMAC128SHA224AuthProtocolOid[9]
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.
error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
Get next usmUserEntry object.
const uint8_t usmNoAuthProtocolOid[9]
error_t snmpUsmMibGetUserSpinLock(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen)
Get usmUserSpinLock object value.
SNMP USM MIB module implementation.
SnmpUsmMibBase snmpUsmMibBase
SNMP USM MIB base.
SNMP USM MIB module.
Common interface for hash algorithms.
Definition: crypto.h:1014
size_t digestSize
Definition: crypto.h:1020
SNMP secret key.
User table entry.
MibRowStatus status
Status of the user.
SnmpKey localizedAuthKey
Localized authentication key.
SnmpPrivProtocol privProtocol
Privacy protocol.
SnmpAuthProtocol authProtocol
Authentication protocol.
SnmpKey localizedPrivKey
Localized privacy key.
SnmpAccess mode
Access mode.
size_t publicValueLen
Length of the public value.
SnmpKey rawPrivKey
Raw privacy key.
char_t name[SNMP_MAX_USER_NAME_LEN+1]
User name.
SnmpKey rawAuthKey
Raw authentication key.
uint8_t publicValue[SNMP_MAX_PUBLIC_VALUE_SIZE]
Public value.
SnmpAgentContext * context
SnmpUserEntry tempUser
uint8_t value[]
Definition: tcp.h:369