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  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL SNMP_TRACE_LEVEL
31 
32 //Dependencies
33 #include "core/net.h"
34 #include "mibs/mib_common.h"
36 #include "mibs/snmp_usm_mib_impl.h"
37 #include "snmp/snmp_agent.h"
38 #include "core/crypto.h"
39 #include "encoding/asn1.h"
40 #include "encoding/oid.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (SNMP_USM_MIB_SUPPORT == ENABLED)
45 
46 //usmNoAuthProtocol OID (1.3.6.1.6.3.10.1.1.1)
47 const uint8_t usmNoAuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 1};
48 //usmHMACMD5AuthProtocol OID (1.3.6.1.6.3.10.1.1.2)
49 const uint8_t usmHMACMD5AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 2};
50 //usmHMACSHAAuthProtocol OID (1.3.6.1.6.3.10.1.1.3)
51 const uint8_t usmHMACSHAAuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 3};
52 //usmHMAC128SHA224AuthProtocol OID (1.3.6.1.6.3.10.1.1.4)
53 const uint8_t usmHMAC128SHA224AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 4};
54 //usmHMAC192SHA256AuthProtocol OID (1.3.6.1.6.3.10.1.1.5)
55 const uint8_t usmHMAC192SHA256AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 5};
56 //usmHMAC256SHA384AuthProtocol OID (1.3.6.1.6.3.10.1.1.6)
57 const uint8_t usmHMAC256SHA384AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 6};
58 //usmHMAC384SHA512AuthProtocol OID (1.3.6.1.6.3.10.1.1.7)
59 const uint8_t usmHMAC384SHA512AuthProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 1, 7};
60 
61 //usmNoPrivProtocol OID (1.3.6.1.6.3.10.1.2.1)
62 const uint8_t usmNoPrivProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 2, 1};
63 //usmDESPrivProtocol OID (1.3.6.1.6.3.10.1.2.2)
64 const uint8_t usmDESPrivProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 2, 2};
65 //usmAesCfb128Protocol OID (1.3.6.1.6.3.10.1.2.4)
66 const uint8_t usmAesCfb128ProtocolOid[9] = {43, 6, 1, 6, 3, 10, 1, 2, 4};
67 
68 //usmUserEntry OID (1.3.6.1.6.3.15.1.2.2.1)
69 const uint8_t usmUserEntryOid[10] = {43, 6, 1, 6, 3, 15, 1, 2, 2, 1};
70 
71 
72 /**
73  * @brief SNMP USM MIB module initialization
74  * @return Error code
75  **/
76 
78 {
79  //Debug message
80  TRACE_INFO("Initializing SNMP-USM-MIB base...\r\n");
81 
82  //Clear SNMP USM MIB base
83  memset(&snmpUsmMibBase, 0, sizeof(snmpUsmMibBase));
84 
85  //usmUserSpinLock object
87 
88  //Successful processing
89  return NO_ERROR;
90 }
91 
92 
93 /**
94  * @brief Load SNMP USM MIB module
95  * @param[in] context Pointer to the SNMP agent context
96  * @return Error code
97  **/
98 
99 error_t snmpUsmMibLoad(void *context)
100 {
101  //Register SNMP agent context
102  snmpUsmMibBase.context = context;
103 
104  //Successful processing
105  return NO_ERROR;
106 }
107 
108 
109 /**
110  * @brief Unload SNMP USM MIB module
111  * @param[in] context Pointer to the SNMP agent context
112  **/
113 
114 void snmpUsmMibUnload(void *context)
115 {
116  //Unregister SNMP agent context
117  snmpUsmMibBase.context = NULL;
118 }
119 
120 
121 /**
122  * @brief Lock SNMP USM MIB base
123  **/
124 
125 void snmpUsmMibLock(void)
126 {
127  //Clear temporary user
128  memset(&snmpUsmMibBase.tempUser, 0, sizeof(SnmpUserEntry));
129 }
130 
131 
132 /**
133  * @brief Unlock SNMP USM MIB base
134  **/
135 
137 {
138  //Clear temporary user
139  memset(&snmpUsmMibBase.tempUser, 0, sizeof(SnmpUserEntry));
140 }
141 
142 
143 /**
144  * @brief Set usmUserSpinLock object value
145  * @param[in] object Pointer to the MIB object descriptor
146  * @param[in] oid Object identifier (object name and instance identifier)
147  * @param[in] oidLen Length of the OID, in bytes
148  * @param[in] value Object value
149  * @param[in] valueLen Length of the object value, in bytes
150  * @param[in] commit This flag tells whether the changes shall be committed
151  * to the MIB base
152  * @return Error code
153  **/
154 
155 error_t snmpUsmMibSetUserSpinLock(const MibObject *object, const uint8_t *oid,
156  size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
157 {
158  //Test and increment spin lock
160  value->integer, commit);
161 }
162 
163 
164 /**
165  * @brief Get usmUserSpinLock object value
166  * @param[in] object Pointer to the MIB object descriptor
167  * @param[in] oid Object identifier (object name and instance identifier)
168  * @param[in] oidLen Length of the OID, in bytes
169  * @param[out] value Object value
170  * @param[in,out] valueLen Length of the object value, in bytes
171  * @return Error code
172  **/
173 
174 error_t snmpUsmMibGetUserSpinLock(const MibObject *object, const uint8_t *oid,
175  size_t oidLen, MibVariant *value, size_t *valueLen)
176 {
177  //Get the current value of the spin lock
179 
180  //Return status code
181  return NO_ERROR;
182 }
183 
184 
185 /**
186  * @brief Set usmUserEntry object value
187  * @param[in] object Pointer to the MIB object descriptor
188  * @param[in] oid Object identifier (object name and instance identifier)
189  * @param[in] oidLen Length of the OID, in bytes
190  * @param[in] value Object value
191  * @param[in] valueLen Length of the object value, in bytes
192  * @param[in] commit This flag tells whether the changes shall be committed
193  * to the MIB base
194  * @return Error code
195  **/
196 
197 error_t snmpUsmMibSetUserEntry(const MibObject *object, const uint8_t *oid,
198  size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
199 {
200  error_t error;
201  size_t n;
202  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
203  size_t userEngineIdLen;
204  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
205  SnmpAgentContext *context;
206  SnmpUserEntry *user;
207 
208  //Point to the instance identifier
209  n = object->oidLen;
210 
211  //usmUserEngineID is used as 1st instance identifier
212  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
213  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
214  //Invalid instance identifier?
215  if(error)
216  return error;
217 
218  //Accept malformed SNMP engine IDs
219  if(n < oidLen && oid[n] == 0)
220  n++;
221 
222  //usmUserName is used as 2nd instance identifier
223  error = mibDecodeString(oid, oidLen, &n, userName,
225  //Invalid instance identifier?
226  if(error)
227  return error;
228 
229  //Sanity check
230  if(n != oidLen)
232 
233  //Make sure the user name is acceptable
234  if(userName[0] == '\0')
236 
237  //Point to the SNMP agent context
239  //Sanity check
240  if(context == NULL)
242 
243  //Retrieve the security profile of the specified user
244  user = snmpFindUserEntry(context, userName, strlen(userName));
245 
246  //usmUserCloneFrom object?
247  if(!strcmp(object->name, "usmUserCloneFrom"))
248  {
249  SnmpUserEntry *cloneFromUser;
250 
251  //Check the length of the OID
252  if(valueLen <= sizeof(usmUserEntryOid))
254 
255  //The OID must point to another conceptual row in the usmUserTable
256  if(memcmp(value->oid, usmUserEntryOid, sizeof(usmUserEntryOid)))
258 
259  //Point to the instance identifier
260  n = sizeof(usmUserEntryOid) + 1;
261 
262  //usmUserEngineID is used as 1st instance identifier
263  error = mibDecodeOctetString(value->oid, valueLen, &n, userEngineId,
264  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
265  //Invalid instance identifier?
266  if(error)
267  return error;
268 
269  //usmUserName is used as 2nd instance identifier
270  error = mibDecodeString(value->oid, valueLen, &n, userName,
272  //Invalid instance identifier?
273  if(error)
274  return error;
275 
276  //Retrieve the security profile of the clone-from user
277  cloneFromUser = snmpFindUserEntry(context, userName, strlen(userName));
278 
279  //The cloning process fails with an inconsistentName error if the
280  //conceptual row representing the clone-from user does not exist or
281  //is not in an active state when the cloning process is invoked
282  if(cloneFromUser == NULL || cloneFromUser->status != MIB_ROW_STATUS_ACTIVE)
284 
285  //Check whether the row has already been instantiated
286  if(user != NULL)
287  {
288  //Commit phase?
289  if(commit)
290  {
291  //The first time an instance of this object is set by a management
292  //operation, the cloning process is invoked
293  if(user->mode == SNMP_ACCESS_NONE)
294  {
295  //Clone the security parameters of the specified user
296  snmpCloneSecurityParameters(user, cloneFromUser);
297  }
298  }
299  }
300  else
301  {
302  //Prepare phase?
303  if(!commit)
304  {
305  //The first time an instance of this object is set by a management
306  //operation, the cloning process is invoked
308  }
309  }
310  }
311  //usmUserAuthProtocol object?
312  else if(!strcmp(object->name, "usmUserAuthProtocol"))
313  {
314  //Check whether the user name exists
315  if(user != NULL)
316  {
317  //If a set operation tries to change the value of an existing instance
318  //of this object to any value other than usmNoAuthProtocol, then an
319  //inconsistentValue error must be returned
320  if(oidComp(value->oid, valueLen, usmNoAuthProtocolOid,
321  sizeof(usmNoAuthProtocolOid)))
322  {
324  }
325 
326  //If a set operation tries to set the value to the usmNoAuthProtocol
327  //while the usmUserPrivProtocol value in the same row is not equal to
328  //usmNoPrivProtocol, then an inconsistentValue error must be returned
331 
332  //Commit phase?
333  if(commit)
334  {
335  //Once instantiated, the value of such an instance of this object
336  //can only be changed via a set operation to the value of the
337  //usmNoAuthProtocol
339  }
340  }
341  else
342  {
343  //Prepare phase?
344  if(!commit)
345  {
346  //The usmUserAuthProtocol object specifies the type of authentication
347  //protocol which is used
348  if(!oidComp(value->oid, valueLen, usmNoAuthProtocolOid,
349  sizeof(usmNoAuthProtocolOid)))
350  {
351  //No authentication
352  }
353  else if(!oidComp(value->oid, valueLen, usmHMACMD5AuthProtocolOid,
354  sizeof(usmHMACMD5AuthProtocolOid)))
355  {
356  //HMAC-MD5-96 authentication protocol
357  }
358  else if(!oidComp(value->oid, valueLen, usmHMACSHAAuthProtocolOid,
359  sizeof(usmHMACSHAAuthProtocolOid)))
360  {
361  //HMAC-SHA-1-96 authentication protocol
362  }
363  else if(!oidComp(value->oid, valueLen, usmHMAC128SHA224AuthProtocolOid,
365  {
366  //HMAC-SHA-224-128 authentication protocol
367  }
368  else if(!oidComp(value->oid, valueLen, usmHMAC192SHA256AuthProtocolOid,
370  {
371  //HMAC-SHA-256-192 authentication protocol
372  }
373  else if(!oidComp(value->oid, valueLen, usmHMAC256SHA384AuthProtocolOid,
375  {
376  //HMAC-SHA-384-256 authentication protocol
377  }
378  else if(!oidComp(value->oid, valueLen, usmHMAC384SHA512AuthProtocolOid,
380  {
381  //HMAC-SHA-512-384 authentication protocol
382  }
383  else
384  {
385  //If an initial set operation (at row creation time) tries to
386  //set a value for an unknown or unsupported protocol, then a
387  //wrongValue error must be returned
388  return ERROR_WRONG_VALUE;
389  }
390  }
391  }
392  }
393  //usmUserAuthKeyChange or usmUserOwnAuthKeyChange object?
394  else if(!strcmp(object->name, "usmUserAuthKeyChange") ||
395  !strcmp(object->name, "usmUserOwnAuthKeyChange"))
396  {
397  const HashAlgo *hashAlgo;
398 
399  //Unknown user name?
400  if(user == NULL)
402 
403  //usmUserOwnAuthKeyChange object?
404  if(!strcmp(object->name, "usmUserOwnAuthKeyChange"))
405  {
406  //When the user name of the requester is not the same as the umsUserName
407  //that indexes the row, then a noAccess error must be returned
408  if(strcmp(user->name, context->user.name))
409  return ERROR_ACCESS_DENIED;
410 
411  //When a set is received and the security model in use is not USM, then
412  //a noAccess error must be returned
413  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
414  return ERROR_ACCESS_DENIED;
415  }
416 
417  //Get the hash algorithm to be used to update the key
418  hashAlgo = snmpGetHashAlgo(user->authProtocol);
419 
420  //Invalid authentication protocol?
421  if(hashAlgo == NULL)
422  return ERROR_WRITE_FAILED;
423 
424  //The value of an instance of this object is the concatenation of
425  //two components of fixed length: first a random component and then
426  //a delta component
427  if(valueLen != (hashAlgo->digestSize * 2))
428  return ERROR_WRONG_LENGTH;
429 
430  //Commit phase?
431  if(commit)
432  {
433  //Update the localized authentication key (Kul)
434  snmpChangeKey(hashAlgo, value->octetString,
435  value->octetString + hashAlgo->digestSize, &user->localizedAuthKey);
436 
437  //The raw authentication key (Ku) is no longer valid
438  memset(&user->rawAuthKey, 0, sizeof(SnmpKey));
439  }
440  }
441  //usmUserPrivProtocol object?
442  else if(!strcmp(object->name, "usmUserPrivProtocol"))
443  {
444  //Check whether the user name exists
445  if(user != NULL)
446  {
447  //If a set operation tries to change the value of an existing instance
448  //of this object to any value other than usmNoPrivProtocol, then an
449  //inconsistentValue error must be returned
450  if(oidComp(value->oid, valueLen, usmNoPrivProtocolOid,
451  sizeof(usmNoPrivProtocolOid)))
452  {
454  }
455 
456  //Commit phase?
457  if(commit)
458  {
459  //Once instantiated, the value of such an instance of this object
460  //can only be changed via a set operation to the value of the
461  //usmNoPrivProtocol
463  }
464  }
465  else
466  {
467  //Prepare phase?
468  if(!commit)
469  {
470  //The usmUserPrivProtocol object specifies the type of privacy
471  //protocol which is used
472  if(!oidComp(value->oid, valueLen, usmNoPrivProtocolOid,
473  sizeof(usmNoPrivProtocolOid)))
474  {
475  //No privacy
476  }
477  else if(!oidComp(value->oid, valueLen, usmDESPrivProtocolOid,
478  sizeof(usmDESPrivProtocolOid)))
479  {
480  //DES-CBC privacy protocol
481  }
482  else if(!oidComp(value->oid, valueLen, usmAesCfb128ProtocolOid,
483  sizeof(usmAesCfb128ProtocolOid)))
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(!strcmp(object->name, "usmUserPrivKeyChange") ||
499  !strcmp(object->name, "usmUserOwnPrivKeyChange"))
500  {
501  const HashAlgo *hashAlgo;
502 
503  //Unknown user name?
504  if(user == NULL)
506 
507  //usmUserOwnPrivKeyChange object?
508  if(!strcmp(object->name, "usmUserOwnPrivKeyChange"))
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(strcmp(user->name, context->user.name))
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  memset(&user->rawPrivKey, 0, sizeof(SnmpKey));
543  }
544  }
545  //usmUserPublic object?
546  else if(!strcmp(object->name, "usmUserPublic"))
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  memcpy(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
574  memcpy(snmpUsmMibBase.tempUser.publicValue, value->octetString,
575  valueLen);
576 
577  //Save the length of the public value
579  }
580  }
581  }
582  //usmUserStorageType object?
583  else if(!strcmp(object->name, "usmUserStorageType"))
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(!strcmp(object->name, "usmUserStatus"))
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  memset(user, 0, sizeof(SnmpUserEntry));
657  //Save user name
658  strcpy(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  memset(user, 0, sizeof(SnmpUserEntry));
701  //Save user name
702  strcpy(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  memset(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 set operation
767  return NO_ERROR;
768 }
769 
770 
771 /**
772  * @brief Get usmUserEntry object value
773  * @param[in] object Pointer to the MIB object descriptor
774  * @param[in] oid Object identifier (object name and instance identifier)
775  * @param[in] oidLen Length of the OID, in bytes
776  * @param[out] value Object value
777  * @param[in,out] valueLen Length of the object value, in bytes
778  * @return Error code
779  **/
780 
781 error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid,
782  size_t oidLen, MibVariant *value, size_t *valueLen)
783 {
784  error_t error;
785  size_t n;
786  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
787  size_t userEngineIdLen;
788  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
789  SnmpAgentContext *context;
790  SnmpUserEntry *user;
791 
792  //Point to the instance identifier
793  n = object->oidLen;
794 
795  //usmUserEngineID is used as 1st instance identifier
796  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
797  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
798  //Invalid instance identifier?
799  if(error)
800  return error;
801 
802  //usmUserName is used as 2nd instance identifier
803  error = mibDecodeString(oid, oidLen, &n, userName,
805  //Invalid instance identifier?
806  if(error)
807  return error;
808 
809  //Sanity check
810  if(n != oidLen)
812 
813  //Point to the SNMP agent context
815  //Sanity check
816  if(context == NULL)
818 
819  //Check the length of the SNMP engine ID
820  if(userEngineIdLen != context->contextEngineLen)
822 
823  //Check SNMP engine ID
824  if(memcmp(userEngineId, context->contextEngine, userEngineIdLen))
826 
827  //Retrieve the security profile of the specified user
828  user = snmpFindUserEntry(context, userName, strlen(userName));
829  //Unknown user name?
830  if(user == NULL)
832 
833  //usmUserSecurityName object?
834  if(!strcmp(object->name, "usmUserSecurityName"))
835  {
836  //The security name is the same as the user name
837  n = strlen(user->name);
838 
839  //Make sure the buffer is large enough to hold the entire object
840  if(*valueLen >= n)
841  {
842  //Copy object value
843  memcpy(value->octetString, user->name, n);
844  //Return object length
845  *valueLen = n;
846  }
847  else
848  {
849  //Report an error
850  error = ERROR_BUFFER_OVERFLOW;
851  }
852  }
853  //usmUserCloneFrom object?
854  else if(!strcmp(object->name, "usmUserCloneFrom"))
855  {
856  //When this object is read, the ZeroDotZero OID is returned
857  uint8_t zeroDotZeroOid[] = {0};
858 
859  //Make sure the buffer is large enough to hold the entire object
860  if(*valueLen >= sizeof(zeroDotZeroOid))
861  {
862  //Copy object value
863  memcpy(value->octetString, zeroDotZeroOid, sizeof(zeroDotZeroOid));
864  //Return object length
865  *valueLen = sizeof(zeroDotZeroOid);
866  }
867  else
868  {
869  //Report an error
870  error = ERROR_BUFFER_OVERFLOW;
871  }
872  }
873  //usmUserAuthProtocol object?
874  else if(!strcmp(object->name, "usmUserAuthProtocol"))
875  {
876  size_t authProtocolLen;
877  const uint8_t *authProtocol;
878 
879  //Check the type of authentication protocol which is used
880  switch(user->authProtocol)
881  {
882  //HMAC-MD5-96 authentication protocol?
884  authProtocol = usmHMACMD5AuthProtocolOid;
885  authProtocolLen = sizeof(usmHMACMD5AuthProtocolOid);
886  break;
887  //HMAC-SHA-1-96 authentication protocol?
889  authProtocol = usmHMACSHAAuthProtocolOid;
890  authProtocolLen = sizeof(usmHMACSHAAuthProtocolOid);
891  break;
892  //HMAC-SHA-224-128 authentication protocol?
894  authProtocol = usmHMAC128SHA224AuthProtocolOid;
895  authProtocolLen = sizeof(usmHMAC128SHA224AuthProtocolOid);
896  break;
897  //HMAC-SHA-256-192 authentication protocol?
899  authProtocol = usmHMAC192SHA256AuthProtocolOid;
900  authProtocolLen = sizeof(usmHMAC192SHA256AuthProtocolOid);
901  break;
902  //HMAC-SHA-384-256 authentication protocol?
904  authProtocol = usmHMAC256SHA384AuthProtocolOid;
905  authProtocolLen = sizeof(usmHMAC256SHA384AuthProtocolOid);
906  break;
907  //HMAC-SHA-512-384 authentication protocol?
909  authProtocol = usmHMAC384SHA512AuthProtocolOid;
910  authProtocolLen = sizeof(usmHMAC384SHA512AuthProtocolOid);
911  break;
912  //No authentication?
913  default:
914  authProtocol = usmNoAuthProtocolOid;
915  authProtocolLen = sizeof(usmNoAuthProtocolOid);
916  break;
917  }
918 
919  //Make sure the buffer is large enough to hold the entire object
920  if(*valueLen >= authProtocolLen)
921  {
922  //Copy object value
923  memcpy(value->octetString, authProtocol, authProtocolLen);
924  //Return object length
925  *valueLen = authProtocolLen;
926  }
927  else
928  {
929  //Report an error
930  error = ERROR_BUFFER_OVERFLOW;
931  }
932  }
933  //usmUserAuthKeyChange object?
934  else if(!strcmp(object->name, "usmUserAuthKeyChange"))
935  {
936  //When this object is read, the zero-length (empty) string is returned
937  *valueLen = 0;
938  }
939  //usmUserOwnAuthKeyChange object?
940  else if(!strcmp(object->name, "usmUserOwnAuthKeyChange"))
941  {
942  //When this object is read, the zero-length (empty) string is returned
943  *valueLen = 0;
944  }
945  //usmUserPrivProtocol object?
946  else if(!strcmp(object->name, "usmUserPrivProtocol"))
947  {
948  size_t privProtocolLen;
949  const uint8_t *privProtocol;
950 
951  //Check the type of privacy protocol which is used
952  switch(user->privProtocol)
953  {
954  //DES-CBC privacy protocol?
956  privProtocol = usmDESPrivProtocolOid;
957  privProtocolLen = sizeof(usmDESPrivProtocolOid);
958  break;
959  //AES-128-CFB privacy protocol?
961  privProtocol = usmAesCfb128ProtocolOid;
962  privProtocolLen = sizeof(usmAesCfb128ProtocolOid);
963  break;
964  //No privacy?
965  default:
966  privProtocol = usmNoPrivProtocolOid;
967  privProtocolLen = sizeof(usmNoPrivProtocolOid);
968  break;
969  }
970 
971  //Make sure the buffer is large enough to hold the entire object
972  if(*valueLen >= privProtocolLen)
973  {
974  //Copy object value
975  memcpy(value->octetString, privProtocol, privProtocolLen);
976  //Return object length
977  *valueLen = privProtocolLen;
978  }
979  else
980  {
981  //Report an error
982  error = ERROR_BUFFER_OVERFLOW;
983  }
984  }
985  //usmUserPrivKeyChange object?
986  else if(!strcmp(object->name, "usmUserPrivKeyChange"))
987  {
988  //When this object is read, the zero-length (empty) string is returned
989  *valueLen = 0;
990  }
991  //usmUserOwnPrivKeyChange object?
992  else if(!strcmp(object->name, "usmUserOwnPrivKeyChange"))
993  {
994  //When this object is read, the zero-length (empty) string is returned
995  *valueLen = 0;
996  }
997  //usmUserPublic object?
998  else if(!strcmp(object->name, "usmUserPublic"))
999  {
1000  //Make sure the buffer is large enough to hold the public value
1001  if(*valueLen >= user->publicValueLen)
1002  {
1003  //The public value can be read to determine whether the change of
1004  //the secret was effected
1005  memcpy(value->octetString, user->publicValue, user->publicValueLen);
1006 
1007  //Return object length
1008  *valueLen = user->publicValueLen;
1009  }
1010  else
1011  {
1012  //Report an error
1013  error = ERROR_BUFFER_OVERFLOW;
1014  }
1015  }
1016  //usmUserStorageType object?
1017  else if(!strcmp(object->name, "usmUserStorageType"))
1018  {
1019  //Get the storage type for this conceptual row
1020  value->integer = MIB_STORAGE_TYPE_VOLATILE;
1021  }
1022  //usmUserStatus object?
1023  else if(!strcmp(object->name, "usmUserStatus"))
1024  {
1025  //Get the status of this conceptual row
1026  value->integer = user->status;
1027  }
1028  //Unknown object?
1029  else
1030  {
1031  //The specified object does not exist
1032  error = ERROR_OBJECT_NOT_FOUND;
1033  }
1034 
1035  //Return status code
1036  return error;
1037 }
1038 
1039 
1040 /**
1041  * @brief Get next usmUserEntry object
1042  * @param[in] object Pointer to the MIB object descriptor
1043  * @param[in] oid Object identifier
1044  * @param[in] oidLen Length of the OID, in bytes
1045  * @param[out] nextOid OID of the next object in the MIB
1046  * @param[out] nextOidLen Length of the next object identifier, in bytes
1047  * @return Error code
1048  **/
1049 
1050 error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid,
1051  size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
1052 {
1053  error_t error;
1054  uint_t i;
1055  size_t n;
1056  bool_t acceptable;
1057  SnmpAgentContext *context;
1058  SnmpUserEntry *entry;
1059  SnmpUserEntry *nextEntry;
1060 
1061  //Initialize variables
1062  nextEntry = NULL;
1063 
1064  //Point to the SNMP agent context
1065  context = (SnmpAgentContext *) snmpUsmMibBase.context;
1066  //Sanity check
1067  if(context == NULL)
1068  return ERROR_OBJECT_NOT_FOUND;
1069 
1070  //Make sure the buffer is large enough to hold the OID prefix
1071  if(*nextOidLen < object->oidLen)
1072  return ERROR_BUFFER_OVERFLOW;
1073 
1074  //Copy OID prefix
1075  memcpy(nextOid, object->oid, object->oidLen);
1076 
1077  //Loop through the list of users
1078  for(i = 0; i < SNMP_AGENT_MAX_USERS; i++)
1079  {
1080  //Point to the current entry
1081  entry = &context->userTable[i];
1082 
1083  //Check the status of the row
1084  if(entry->status != MIB_ROW_STATUS_UNUSED)
1085  {
1086  //Append the instance identifier to the OID prefix
1087  n = object->oidLen;
1088 
1089  //usmUserEngineID is used as 1st instance identifier
1090  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1091  context->contextEngine, context->contextEngineLen, FALSE);
1092  //Any error to report?
1093  if(error)
1094  return error;
1095 
1096  //usmUserName is used as 2nd instance identifier
1097  error = mibEncodeString(nextOid, *nextOidLen, &n, entry->name, FALSE);
1098  //Any error to report?
1099  if(error)
1100  return error;
1101 
1102  //Check whether the resulting object identifier lexicographically
1103  //follows the specified OID
1104  if(oidComp(nextOid, n, oid, oidLen) > 0)
1105  {
1106  //Perform lexicographic comparison
1107  if(nextEntry == NULL)
1108  acceptable = TRUE;
1109  else if(strlen(entry->name) < strlen(nextEntry->name))
1110  acceptable = TRUE;
1111  else if(strlen(entry->name) > strlen(nextEntry->name))
1112  acceptable = FALSE;
1113  else if(strcmp(entry->name, nextEntry->name) < 0)
1114  acceptable = TRUE;
1115  else
1116  acceptable = FALSE;
1117 
1118  //Save the closest object identifier that follows the specified
1119  //OID in lexicographic order
1120  if(acceptable)
1121  nextEntry = entry;
1122  }
1123  }
1124  }
1125 
1126  //The specified OID does not lexicographically precede the name
1127  //of some object?
1128  if(nextEntry == NULL)
1129  return ERROR_OBJECT_NOT_FOUND;
1130 
1131  //Append the instance identifier to the OID prefix
1132  n = object->oidLen;
1133 
1134  //usmUserEngineID is used as 1st instance identifier
1135  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1136  context->contextEngine, context->contextEngineLen, FALSE);
1137  //Any error to report?
1138  if(error)
1139  return error;
1140 
1141  //usmUserName is used as 2nd instance identifier
1142  error = mibEncodeString(nextOid, *nextOidLen, &n, nextEntry->name, FALSE);
1143  //Any error to report?
1144  if(error)
1145  return error;
1146 
1147  //Save the length of the resulting object identifier
1148  *nextOidLen = n;
1149  //Next object found
1150  return NO_ERROR;
1151 }
1152 
1153 #endif
HMAC-SHA-384-256.
SnmpUserEntry * snmpFindUserEntry(SnmpAgentContext *context, const char_t *name, size_t length)
Search the user table for a given user name.
SnmpAgentContext * context
SNMP USM MIB module implementation.
SnmpPrivProtocol privProtocol
Privacy protocol.
char char_t
Definition: compiler_port.h:41
MibRowStatus status
Status of the user.
const uint8_t usmNoAuthProtocolOid[9]
uint8_t publicValue[SNMP_MAX_PUBLIC_VALUE_SIZE]
Public value.
SnmpUserEntry tempUser
SnmpUsmMibBase snmpUsmMibBase
SNMP USM MIB base.
TCP/IP stack core.
Debugging facilities.
SnmpKey localizedAuthKey
Localized authentication key.
const uint8_t usmHMACMD5AuthProtocolOid[9]
#define SNMP_AGENT_MAX_USERS
Definition: snmp_agent.h:81
MibRowStatus
Row status.
Definition: mib_common.h:98
User-based security model.
SnmpKey rawPrivKey
Raw privacy key.
#define MibObject
Definition: mib_common.h:44
General definitions for cryptographic algorithms.
void snmpUsmMibUnlock(void)
Unlock SNMP USM MIB base.
#define SNMP_MAX_CONTEXT_ENGINE_SIZE
Definition: snmp_common.h:65
HMAC-SHA-224-128.
error_t snmpUsmMibInit(void)
SNMP USM MIB module initialization.
#define SNMP_MAX_PUBLIC_VALUE_SIZE
Definition: snmp_common.h:86
User table entry.
const uint8_t usmHMAC256SHA384AuthProtocolOid[9]
OID (Object Identifier)
#define TRUE
Definition: os_port.h:48
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.
#define SNMP_MAX_USER_NAME_LEN
Definition: snmp_common.h:79
ASN.1 (Abstract Syntax Notation One)
error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen)
Get usmUserEntry object value.
SNMP agent (Simple Network Management Protocol)
void snmpUsmMibLock(void)
Lock SNMP USM MIB base.
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:147
SnmpUserEntry * snmpCreateUserEntry(SnmpAgentContext *context)
Create a new user entry.
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:180
SNMP USM MIB module.
const uint8_t usmDESPrivProtocolOid[9]
SnmpAccess mode
Access mode.
SnmpKey localizedPrivKey
Localized privacy key.
error_t snmpUsmMibGetUserSpinLock(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen)
Get usmUserSpinLock object value.
int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2, size_t oidLen2)
Compare object identifiers.
Definition: oid.c:99
HMAC-SHA-256-192.
#define TRACE_INFO(...)
Definition: debug.h:86
const uint8_t usmAesCfb128ProtocolOid[9]
Success.
Definition: error.h:42
HMAC-SHA-512-384.
void snmpCloneSecurityParameters(SnmpUserEntry *user, const SnmpUserEntry *cloneFromUser)
Clone security parameters.
int32_t netGetRandRange(int32_t min, int32_t max)
Get a random value in the specified range.
Definition: net.c:1554
error_t
Error codes.
Definition: error.h:40
size_t publicValueLen
Length of the public value.
__start_packed struct @208 MibVariant
Variant data type.
unsigned int uint_t
Definition: compiler_port.h:43
const uint8_t usmNoPrivProtocolOid[9]
const uint8_t usmUserEntryOid[10]
void snmpUsmMibUnload(void *context)
Unload SNMP USM MIB module.
char_t name[SNMP_MAX_USER_NAME_LEN+1]
User name.
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:127
SNMP secret key.
error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
Get next usmUserEntry object.
uint8_t value[]
Definition: dtls_misc.h:141
const uint8_t usmHMAC192SHA256AuthProtocolOid[9]
Common definitions for MIB modules.
SnmpAuthProtocol authProtocol
Authentication protocol.
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.
const HashAlgo * snmpGetHashAlgo(SnmpAuthProtocol authProtocol)
Get the hash algorithm to be used for a given authentication protocol.
#define SnmpAgentContext
Definition: snmp_agent.h:34
const uint8_t usmHMACSHAAuthProtocolOid[9]
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:223
error_t snmpUsmMibLoad(void *context)
Load 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:939
size_t digestSize
Definition: crypto.h:1061
Common interface for hash algorithms.
Definition: crypto.h:1054
uint8_t n
uint8_t oid[1]
Definition: mib_common.h:184
const uint8_t usmHMAC128SHA224AuthProtocolOid[9]
#define FALSE
Definition: os_port.h:44
int bool_t
Definition: compiler_port.h:47
const uint8_t usmHMAC384SHA512AuthProtocolOid[9]
SnmpKey rawAuthKey
Raw authentication key.
void snmpChangeKey(const HashAlgo *hashAlgo, const uint8_t *random, const uint8_t *delta, SnmpKey *key)
Change secret key.