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-2019 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 1.9.6
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
85  memset(&snmpUsmMibBase, 0, sizeof(snmpUsmMibBase));
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
130  memset(&snmpUsmMibBase.tempUser, 0, sizeof(SnmpUserEntry));
131 }
132 
133 
134 /**
135  * @brief Unlock SNMP USM MIB base
136  **/
137 
139 {
140  //Clear temporary user
141  memset(&snmpUsmMibBase.tempUser, 0, sizeof(SnmpUserEntry));
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  //Return status code
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  error_t error;
203  size_t n;
204  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
205  size_t userEngineIdLen;
206  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
207  SnmpAgentContext *context;
208  SnmpUserEntry *user;
209 
210  //Point to the instance identifier
211  n = object->oidLen;
212 
213  //usmUserEngineID is used as 1st instance identifier
214  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
215  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
216  //Invalid instance identifier?
217  if(error)
218  return error;
219 
220  //Accept malformed SNMP engine IDs
221  if(n < oidLen && oid[n] == 0)
222  n++;
223 
224  //usmUserName is used as 2nd instance identifier
225  error = mibDecodeString(oid, oidLen, &n, userName,
227  //Invalid instance identifier?
228  if(error)
229  return error;
230 
231  //Sanity check
232  if(n != oidLen)
234 
235  //Make sure the user name is acceptable
236  if(userName[0] == '\0')
238 
239  //Point to the SNMP agent context
241  //Sanity check
242  if(context == NULL)
244 
245  //Retrieve the security profile of the specified user
246  user = snmpFindUserEntry(context, userName, strlen(userName));
247 
248  //usmUserCloneFrom object?
249  if(!strcmp(object->name, "usmUserCloneFrom"))
250  {
251  SnmpUserEntry *cloneFromUser;
252 
253  //Check the length of the OID
254  if(valueLen <= sizeof(usmUserEntryOid))
256 
257  //The OID must point to another conceptual row in the usmUserTable
258  if(memcmp(value->oid, usmUserEntryOid, sizeof(usmUserEntryOid)))
260 
261  //Point to the instance identifier
262  n = sizeof(usmUserEntryOid) + 1;
263 
264  //usmUserEngineID is used as 1st instance identifier
265  error = mibDecodeOctetString(value->oid, valueLen, &n, userEngineId,
266  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
267  //Invalid instance identifier?
268  if(error)
269  return error;
270 
271  //usmUserName is used as 2nd instance identifier
272  error = mibDecodeString(value->oid, valueLen, &n, userName,
274  //Invalid instance identifier?
275  if(error)
276  return error;
277 
278  //Retrieve the security profile of the clone-from user
279  cloneFromUser = snmpFindUserEntry(context, userName, strlen(userName));
280 
281  //The cloning process fails with an inconsistentName error if the
282  //conceptual row representing the clone-from user does not exist or
283  //is not in an active state when the cloning process is invoked
284  if(cloneFromUser == NULL || cloneFromUser->status != MIB_ROW_STATUS_ACTIVE)
286 
287  //Check whether the row has already been instantiated
288  if(user != NULL)
289  {
290  //Commit phase?
291  if(commit)
292  {
293  //The first time an instance of this object is set by a management
294  //operation, the cloning process is invoked
295  if(user->mode == SNMP_ACCESS_NONE)
296  {
297  //Clone the security parameters of the specified user
298  snmpCloneSecurityParameters(user, cloneFromUser);
299  }
300  }
301  }
302  else
303  {
304  //Prepare phase?
305  if(!commit)
306  {
307  //The first time an instance of this object is set by a management
308  //operation, the cloning process is invoked
310  }
311  }
312  }
313  //usmUserAuthProtocol object?
314  else if(!strcmp(object->name, "usmUserAuthProtocol"))
315  {
316  //Check whether the user name exists
317  if(user != NULL)
318  {
319  //If a set operation tries to change the value of an existing instance
320  //of this object to any value other than usmNoAuthProtocol, then an
321  //inconsistentValue error must be returned
322  if(oidComp(value->oid, valueLen, usmNoAuthProtocolOid,
323  sizeof(usmNoAuthProtocolOid)))
324  {
326  }
327 
328  //If a set operation tries to set the value to the usmNoAuthProtocol
329  //while the usmUserPrivProtocol value in the same row is not equal to
330  //usmNoPrivProtocol, then an inconsistentValue error must be returned
333 
334  //Commit phase?
335  if(commit)
336  {
337  //Once instantiated, the value of such an instance of this object
338  //can only be changed via a set operation to the value of the
339  //usmNoAuthProtocol
341  }
342  }
343  else
344  {
345  //Prepare phase?
346  if(!commit)
347  {
348  //The usmUserAuthProtocol object specifies the type of authentication
349  //protocol which is used
350  if(!oidComp(value->oid, valueLen, usmNoAuthProtocolOid,
351  sizeof(usmNoAuthProtocolOid)))
352  {
353  //No authentication
354  }
355  else if(!oidComp(value->oid, valueLen, usmHMACMD5AuthProtocolOid,
356  sizeof(usmHMACMD5AuthProtocolOid)))
357  {
358  //HMAC-MD5-96 authentication protocol
359  }
360  else if(!oidComp(value->oid, valueLen, usmHMACSHAAuthProtocolOid,
361  sizeof(usmHMACSHAAuthProtocolOid)))
362  {
363  //HMAC-SHA-1-96 authentication protocol
364  }
365  else if(!oidComp(value->oid, valueLen, usmHMAC128SHA224AuthProtocolOid,
367  {
368  //HMAC-SHA-224-128 authentication protocol
369  }
370  else if(!oidComp(value->oid, valueLen, usmHMAC192SHA256AuthProtocolOid,
372  {
373  //HMAC-SHA-256-192 authentication protocol
374  }
375  else if(!oidComp(value->oid, valueLen, usmHMAC256SHA384AuthProtocolOid,
377  {
378  //HMAC-SHA-384-256 authentication protocol
379  }
380  else if(!oidComp(value->oid, valueLen, usmHMAC384SHA512AuthProtocolOid,
382  {
383  //HMAC-SHA-512-384 authentication protocol
384  }
385  else
386  {
387  //If an initial set operation (at row creation time) tries to
388  //set a value for an unknown or unsupported protocol, then a
389  //wrongValue error must be returned
390  return ERROR_WRONG_VALUE;
391  }
392  }
393  }
394  }
395  //usmUserAuthKeyChange or usmUserOwnAuthKeyChange object?
396  else if(!strcmp(object->name, "usmUserAuthKeyChange") ||
397  !strcmp(object->name, "usmUserOwnAuthKeyChange"))
398  {
399  const HashAlgo *hashAlgo;
400 
401  //Unknown user name?
402  if(user == NULL)
404 
405  //usmUserOwnAuthKeyChange object?
406  if(!strcmp(object->name, "usmUserOwnAuthKeyChange"))
407  {
408  //When the user name of the requester is not the same as the umsUserName
409  //that indexes the row, then a noAccess error must be returned
410  if(strcmp(user->name, context->user.name))
411  return ERROR_ACCESS_DENIED;
412 
413  //When a set is received and the security model in use is not USM, then
414  //a noAccess error must be returned
415  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
416  return ERROR_ACCESS_DENIED;
417  }
418 
419  //Get the hash algorithm to be used to update the key
420  hashAlgo = snmpGetHashAlgo(user->authProtocol);
421 
422  //Invalid authentication protocol?
423  if(hashAlgo == NULL)
424  return ERROR_WRITE_FAILED;
425 
426  //The value of an instance of this object is the concatenation of
427  //two components of fixed length: first a random component and then
428  //a delta component
429  if(valueLen != (hashAlgo->digestSize * 2))
430  return ERROR_WRONG_LENGTH;
431 
432  //Commit phase?
433  if(commit)
434  {
435  //Update the localized authentication key (Kul)
436  snmpChangeKey(hashAlgo, value->octetString,
437  value->octetString + hashAlgo->digestSize, &user->localizedAuthKey);
438 
439  //The raw authentication key (Ku) is no longer valid
440  memset(&user->rawAuthKey, 0, sizeof(SnmpKey));
441  }
442  }
443  //usmUserPrivProtocol object?
444  else if(!strcmp(object->name, "usmUserPrivProtocol"))
445  {
446  //Check whether the user name exists
447  if(user != NULL)
448  {
449  //If a set operation tries to change the value of an existing instance
450  //of this object to any value other than usmNoPrivProtocol, then an
451  //inconsistentValue error must be returned
452  if(oidComp(value->oid, valueLen, usmNoPrivProtocolOid,
453  sizeof(usmNoPrivProtocolOid)))
454  {
456  }
457 
458  //Commit phase?
459  if(commit)
460  {
461  //Once instantiated, the value of such an instance of this object
462  //can only be changed via a set operation to the value of the
463  //usmNoPrivProtocol
465  }
466  }
467  else
468  {
469  //Prepare phase?
470  if(!commit)
471  {
472  //The usmUserPrivProtocol object specifies the type of privacy
473  //protocol which is used
474  if(!oidComp(value->oid, valueLen, usmNoPrivProtocolOid,
475  sizeof(usmNoPrivProtocolOid)))
476  {
477  //No privacy
478  }
479  else if(!oidComp(value->oid, valueLen, usmDESPrivProtocolOid,
480  sizeof(usmDESPrivProtocolOid)))
481  {
482  //DES-CBC privacy protocol
483  }
484  else if(!oidComp(value->oid, valueLen, usmAesCfb128ProtocolOid,
485  sizeof(usmAesCfb128ProtocolOid)))
486  {
487  //AES-128-CFB privacy protocol
488  }
489  else
490  {
491  //If an initial set operation (at row creation time) tries to
492  //set a value for an unknown or unsupported protocol, then a
493  //wrongValue error must be returned
494  return ERROR_WRONG_VALUE;
495  }
496  }
497  }
498  }
499  //usmUserPrivKeyChange or usmUserOwnPrivKeyChangeobject?
500  else if(!strcmp(object->name, "usmUserPrivKeyChange") ||
501  !strcmp(object->name, "usmUserOwnPrivKeyChange"))
502  {
503  const HashAlgo *hashAlgo;
504 
505  //Unknown user name?
506  if(user == NULL)
508 
509  //usmUserOwnPrivKeyChange object?
510  if(!strcmp(object->name, "usmUserOwnPrivKeyChange"))
511  {
512  //When the user name of the requester is not the same as the umsUserName
513  //that indexes the row, then a noAccess error must be returned
514  if(strcmp(user->name, context->user.name))
515  return ERROR_ACCESS_DENIED;
516 
517  //When a set is received and the security model in use is not USM, then
518  //a noAccess error must be returned
519  if(context->request.msgSecurityModel != SNMP_SECURITY_MODEL_USM)
520  return ERROR_ACCESS_DENIED;
521  }
522 
523  //Get the hash algorithm to be used to update the key
524  hashAlgo = snmpGetHashAlgo(user->authProtocol);
525 
526  //Invalid authentication protocol?
527  if(hashAlgo == NULL)
528  return ERROR_WRITE_FAILED;
529 
530  //The value of an instance of this object is the concatenation of
531  //two components of fixed length: first a random component and then
532  //a delta component
533  if(valueLen != (hashAlgo->digestSize * 2))
534  return ERROR_WRONG_LENGTH;
535 
536  //Commit phase?
537  if(commit)
538  {
539  //Update the localized privacy key (Kul)
540  snmpChangeKey(hashAlgo, value->octetString,
541  value->octetString + hashAlgo->digestSize, &user->localizedPrivKey);
542 
543  //The raw privacy key (Ku) is no longer valid
544  memset(&user->rawPrivKey, 0, sizeof(SnmpKey));
545  }
546  }
547  //usmUserPublic object?
548  else if(!strcmp(object->name, "usmUserPublic"))
549  {
550  //Check the length of the public value
551  if(valueLen > SNMP_MAX_PUBLIC_VALUE_SIZE)
552  return ERROR_WRONG_LENGTH;
553 
554  //Check whether the user name exists
555  if(user != NULL)
556  {
557  //Commit phase?
558  if(commit)
559  {
560  //The usmUserPublic can be written as part of the procedure for
561  //changing a user's secret authentication and/or privacy key,
562  //and later read to determine whether the change of the secret
563  //was effected
564  memcpy(user->publicValue, value->octetString, valueLen);
565 
566  //Update the length of the public value
567  user->publicValueLen = valueLen;
568  }
569  }
570  else
571  {
572  //Prepare phase?
573  if(!commit)
574  {
575  //Save the value of the public value for later use
576  memcpy(snmpUsmMibBase.tempUser.publicValue, value->octetString,
577  valueLen);
578 
579  //Save the length of the public value
581  }
582  }
583  }
584  //usmUserStorageType object?
585  else if(!strcmp(object->name, "usmUserStorageType"))
586  {
587  //The usmUserStorageType object specifies the storage type for this
588  //conceptual row
589  if(value->integer != MIB_STORAGE_TYPE_OTHER &&
590  value->integer != MIB_STORAGE_TYPE_VOLATILE &&
591  value->integer != MIB_STORAGE_TYPE_NON_VOLATILE &&
592  value->integer != MIB_STORAGE_TYPE_PERMANENT &&
593  value->integer != MIB_STORAGE_TYPE_READ_ONLY)
594  {
595  return ERROR_WRONG_VALUE;
596  }
597  }
598  //usmUserStatus object?
599  else if(!strcmp(object->name, "usmUserStatus"))
600  {
601  MibRowStatus status;
602 
603  //Get row status
604  status = (MibRowStatus) value->integer;
605 
606  //Check the value specified by the set operation
607  if(status == MIB_ROW_STATUS_ACTIVE ||
609  {
610  //Unknown user name?
611  if(user == NULL)
613 
614  //Commit phase?
615  if(commit)
616  {
617  //The first time an instance of this object is set by a management
618  //operation, the cloning process is invoked
619  if(user->mode == SNMP_ACCESS_NONE)
620  {
621  //Valid clone-from user?
623  {
624  //Copy the security profile of the clone-from user
626  }
627  }
628 
629  //When the agent processes the set operation, it verifies that it
630  //has sufficient information to make the conceptual row available
631  //for use by the managed device
632  if(user->mode == SNMP_ACCESS_NONE)
634 
635  //Update the status of the conceptual row
636  user->status = status;
637  }
638  }
639  else if(status == MIB_ROW_STATUS_CREATE_AND_GO)
640  {
641  //User name already in use?
642  if(user != NULL)
644 
645  //Create a security profile for the new user
646  user = snmpCreateUserEntry(context);
647  //Unable to create a new user?
648  if(user == NULL)
649  return ERROR_WRITE_FAILED;
650 
651  //Commit phase?
652  if(commit)
653  {
654  //Valid clone-from user?
656  {
657  //Clear the security profile of the user
658  memset(user, 0, sizeof(SnmpUserEntry));
659  //Save user name
660  strcpy(user->name, userName);
661 
662  //Valid public value specified?
664  {
665  //Copy the public value
668 
669  //Set the length of the public value
671  }
672 
673  //Copy the security profile of the clone-from user
675 
676  //The conceptual row is now available for use by the managed device
678  }
679  else
680  {
681  //The newly created row cannot be made active
683  }
684  }
685  }
686  else if(status == MIB_ROW_STATUS_CREATE_AND_WAIT)
687  {
688  //User name already in use?
689  if(user != NULL)
691 
692  //Create a security profile for the new user
693  user = snmpCreateUserEntry(context);
694  //Unable to create a new user?
695  if(user == NULL)
696  return ERROR_WRITE_FAILED;
697 
698  //Commit phase?
699  if(commit)
700  {
701  //Clear the security profile of the user
702  memset(user, 0, sizeof(SnmpUserEntry));
703  //Save user name
704  strcpy(user->name, userName);
705 
706  //Valid public value specified?
708  {
709  //Copy the public value
712 
713  //Set the length of the public value
715  }
716 
717  //Check whether the cloning process has been invoked
718  if(user->mode != SNMP_ACCESS_NONE)
719  {
720  //Copy the security profile of the clone-from user
722 
723  //Instances of all corresponding columns are now configured
725  }
726  else
727  {
728  //Initialize columns with default values
731 
732  //Until instances of all corresponding columns are appropriately
733  //configured, the value of the corresponding instance of the
734  //usmUserStatus column is notReady
736  }
737  }
738  }
739  else if(status == MIB_ROW_STATUS_DESTROY)
740  {
741  //Check whether the user name exists
742  if(user != NULL)
743  {
744  //Commit phase?
745  if(commit)
746  {
747  //Clear the security profile of the user
748  memset(user, 0, sizeof(SnmpUserEntry));
749 
750  //Delete the conceptual row from the table
752  }
753  }
754  }
755  else
756  {
757  //Unsupported action
759  }
760  }
761  //Unknown object?
762  else
763  {
764  //The specified object does not exist
765  return ERROR_OBJECT_NOT_FOUND;
766  }
767 
768  //Successful set operation
769  return NO_ERROR;
770 }
771 
772 
773 /**
774  * @brief Get usmUserEntry object value
775  * @param[in] object Pointer to the MIB object descriptor
776  * @param[in] oid Object identifier (object name and instance identifier)
777  * @param[in] oidLen Length of the OID, in bytes
778  * @param[out] value Object value
779  * @param[in,out] valueLen Length of the object value, in bytes
780  * @return Error code
781  **/
782 
783 error_t snmpUsmMibGetUserEntry(const MibObject *object, const uint8_t *oid,
784  size_t oidLen, MibVariant *value, size_t *valueLen)
785 {
786  error_t error;
787  size_t n;
788  uint8_t userEngineId[SNMP_MAX_CONTEXT_ENGINE_SIZE];
789  size_t userEngineIdLen;
790  char_t userName[SNMP_MAX_USER_NAME_LEN + 1];
791  SnmpAgentContext *context;
792  SnmpUserEntry *user;
793 
794  //Point to the instance identifier
795  n = object->oidLen;
796 
797  //usmUserEngineID is used as 1st instance identifier
798  error = mibDecodeOctetString(oid, oidLen, &n, userEngineId,
799  SNMP_MAX_CONTEXT_ENGINE_SIZE, &userEngineIdLen, FALSE);
800  //Invalid instance identifier?
801  if(error)
802  return error;
803 
804  //usmUserName is used as 2nd instance identifier
805  error = mibDecodeString(oid, oidLen, &n, userName,
807  //Invalid instance identifier?
808  if(error)
809  return error;
810 
811  //Sanity check
812  if(n != oidLen)
814 
815  //Point to the SNMP agent context
817  //Sanity check
818  if(context == NULL)
820 
821  //Check the length of the SNMP engine ID
822  if(userEngineIdLen != context->contextEngineLen)
824 
825  //Check SNMP engine ID
826  if(memcmp(userEngineId, context->contextEngine, userEngineIdLen))
828 
829  //Retrieve the security profile of the specified user
830  user = snmpFindUserEntry(context, userName, strlen(userName));
831  //Unknown user name?
832  if(user == NULL)
834 
835  //usmUserSecurityName object?
836  if(!strcmp(object->name, "usmUserSecurityName"))
837  {
838  //The security name is the same as the user name
839  n = strlen(user->name);
840 
841  //Make sure the buffer is large enough to hold the entire object
842  if(*valueLen >= n)
843  {
844  //Copy object value
845  memcpy(value->octetString, user->name, n);
846  //Return object length
847  *valueLen = n;
848  }
849  else
850  {
851  //Report an error
852  error = ERROR_BUFFER_OVERFLOW;
853  }
854  }
855  //usmUserCloneFrom object?
856  else if(!strcmp(object->name, "usmUserCloneFrom"))
857  {
858  //When this object is read, the ZeroDotZero OID is returned
859  uint8_t zeroDotZeroOid[] = {0};
860 
861  //Make sure the buffer is large enough to hold the entire object
862  if(*valueLen >= sizeof(zeroDotZeroOid))
863  {
864  //Copy object value
865  memcpy(value->octetString, zeroDotZeroOid, sizeof(zeroDotZeroOid));
866  //Return object length
867  *valueLen = sizeof(zeroDotZeroOid);
868  }
869  else
870  {
871  //Report an error
872  error = ERROR_BUFFER_OVERFLOW;
873  }
874  }
875  //usmUserAuthProtocol object?
876  else if(!strcmp(object->name, "usmUserAuthProtocol"))
877  {
878  size_t authProtocolLen;
879  const uint8_t *authProtocol;
880 
881  //Check the type of authentication protocol which is used
882  switch(user->authProtocol)
883  {
884  //HMAC-MD5-96 authentication protocol?
886  authProtocol = usmHMACMD5AuthProtocolOid;
887  authProtocolLen = sizeof(usmHMACMD5AuthProtocolOid);
888  break;
889  //HMAC-SHA-1-96 authentication protocol?
891  authProtocol = usmHMACSHAAuthProtocolOid;
892  authProtocolLen = sizeof(usmHMACSHAAuthProtocolOid);
893  break;
894  //HMAC-SHA-224-128 authentication protocol?
896  authProtocol = usmHMAC128SHA224AuthProtocolOid;
897  authProtocolLen = sizeof(usmHMAC128SHA224AuthProtocolOid);
898  break;
899  //HMAC-SHA-256-192 authentication protocol?
901  authProtocol = usmHMAC192SHA256AuthProtocolOid;
902  authProtocolLen = sizeof(usmHMAC192SHA256AuthProtocolOid);
903  break;
904  //HMAC-SHA-384-256 authentication protocol?
906  authProtocol = usmHMAC256SHA384AuthProtocolOid;
907  authProtocolLen = sizeof(usmHMAC256SHA384AuthProtocolOid);
908  break;
909  //HMAC-SHA-512-384 authentication protocol?
911  authProtocol = usmHMAC384SHA512AuthProtocolOid;
912  authProtocolLen = sizeof(usmHMAC384SHA512AuthProtocolOid);
913  break;
914  //No authentication?
915  default:
916  authProtocol = usmNoAuthProtocolOid;
917  authProtocolLen = sizeof(usmNoAuthProtocolOid);
918  break;
919  }
920 
921  //Make sure the buffer is large enough to hold the entire object
922  if(*valueLen >= authProtocolLen)
923  {
924  //Copy object value
925  memcpy(value->octetString, authProtocol, authProtocolLen);
926  //Return object length
927  *valueLen = authProtocolLen;
928  }
929  else
930  {
931  //Report an error
932  error = ERROR_BUFFER_OVERFLOW;
933  }
934  }
935  //usmUserAuthKeyChange object?
936  else if(!strcmp(object->name, "usmUserAuthKeyChange"))
937  {
938  //When this object is read, the zero-length (empty) string is returned
939  *valueLen = 0;
940  }
941  //usmUserOwnAuthKeyChange object?
942  else if(!strcmp(object->name, "usmUserOwnAuthKeyChange"))
943  {
944  //When this object is read, the zero-length (empty) string is returned
945  *valueLen = 0;
946  }
947  //usmUserPrivProtocol object?
948  else if(!strcmp(object->name, "usmUserPrivProtocol"))
949  {
950  size_t privProtocolLen;
951  const uint8_t *privProtocol;
952 
953  //Check the type of privacy protocol which is used
954  switch(user->privProtocol)
955  {
956  //DES-CBC privacy protocol?
958  privProtocol = usmDESPrivProtocolOid;
959  privProtocolLen = sizeof(usmDESPrivProtocolOid);
960  break;
961  //AES-128-CFB privacy protocol?
963  privProtocol = usmAesCfb128ProtocolOid;
964  privProtocolLen = sizeof(usmAesCfb128ProtocolOid);
965  break;
966  //No privacy?
967  default:
968  privProtocol = usmNoPrivProtocolOid;
969  privProtocolLen = sizeof(usmNoPrivProtocolOid);
970  break;
971  }
972 
973  //Make sure the buffer is large enough to hold the entire object
974  if(*valueLen >= privProtocolLen)
975  {
976  //Copy object value
977  memcpy(value->octetString, privProtocol, privProtocolLen);
978  //Return object length
979  *valueLen = privProtocolLen;
980  }
981  else
982  {
983  //Report an error
984  error = ERROR_BUFFER_OVERFLOW;
985  }
986  }
987  //usmUserPrivKeyChange object?
988  else if(!strcmp(object->name, "usmUserPrivKeyChange"))
989  {
990  //When this object is read, the zero-length (empty) string is returned
991  *valueLen = 0;
992  }
993  //usmUserOwnPrivKeyChange object?
994  else if(!strcmp(object->name, "usmUserOwnPrivKeyChange"))
995  {
996  //When this object is read, the zero-length (empty) string is returned
997  *valueLen = 0;
998  }
999  //usmUserPublic object?
1000  else if(!strcmp(object->name, "usmUserPublic"))
1001  {
1002  //Make sure the buffer is large enough to hold the public value
1003  if(*valueLen >= user->publicValueLen)
1004  {
1005  //The public value can be read to determine whether the change of
1006  //the secret was effected
1007  memcpy(value->octetString, user->publicValue, user->publicValueLen);
1008 
1009  //Return object length
1010  *valueLen = user->publicValueLen;
1011  }
1012  else
1013  {
1014  //Report an error
1015  error = ERROR_BUFFER_OVERFLOW;
1016  }
1017  }
1018  //usmUserStorageType object?
1019  else if(!strcmp(object->name, "usmUserStorageType"))
1020  {
1021  //Get the storage type for this conceptual row
1022  value->integer = MIB_STORAGE_TYPE_VOLATILE;
1023  }
1024  //usmUserStatus object?
1025  else if(!strcmp(object->name, "usmUserStatus"))
1026  {
1027  //Get the status of this conceptual row
1028  value->integer = user->status;
1029  }
1030  //Unknown object?
1031  else
1032  {
1033  //The specified object does not exist
1034  error = ERROR_OBJECT_NOT_FOUND;
1035  }
1036 
1037  //Return status code
1038  return error;
1039 }
1040 
1041 
1042 /**
1043  * @brief Get next usmUserEntry object
1044  * @param[in] object Pointer to the MIB object descriptor
1045  * @param[in] oid Object identifier
1046  * @param[in] oidLen Length of the OID, in bytes
1047  * @param[out] nextOid OID of the next object in the MIB
1048  * @param[out] nextOidLen Length of the next object identifier, in bytes
1049  * @return Error code
1050  **/
1051 
1052 error_t snmpUsmMibGetNextUserEntry(const MibObject *object, const uint8_t *oid,
1053  size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
1054 {
1055  error_t error;
1056  uint_t i;
1057  size_t n;
1058  bool_t acceptable;
1059  SnmpAgentContext *context;
1060  SnmpUserEntry *entry;
1061  SnmpUserEntry *nextEntry;
1062 
1063  //Initialize variables
1064  nextEntry = NULL;
1065 
1066  //Point to the SNMP agent context
1067  context = (SnmpAgentContext *) snmpUsmMibBase.context;
1068  //Sanity check
1069  if(context == NULL)
1070  return ERROR_OBJECT_NOT_FOUND;
1071 
1072  //Make sure the buffer is large enough to hold the OID prefix
1073  if(*nextOidLen < object->oidLen)
1074  return ERROR_BUFFER_OVERFLOW;
1075 
1076  //Copy OID prefix
1077  memcpy(nextOid, object->oid, object->oidLen);
1078 
1079  //Loop through the list of users
1080  for(i = 0; i < SNMP_AGENT_MAX_USERS; i++)
1081  {
1082  //Point to the current entry
1083  entry = &context->userTable[i];
1084 
1085  //Check the status of the row
1086  if(entry->status != MIB_ROW_STATUS_UNUSED)
1087  {
1088  //Append the instance identifier to the OID prefix
1089  n = object->oidLen;
1090 
1091  //usmUserEngineID is used as 1st instance identifier
1092  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1093  context->contextEngine, context->contextEngineLen, FALSE);
1094  //Any error to report?
1095  if(error)
1096  return error;
1097 
1098  //usmUserName is used as 2nd instance identifier
1099  error = mibEncodeString(nextOid, *nextOidLen, &n, entry->name, FALSE);
1100  //Any error to report?
1101  if(error)
1102  return error;
1103 
1104  //Check whether the resulting object identifier lexicographically
1105  //follows the specified OID
1106  if(oidComp(nextOid, n, oid, oidLen) > 0)
1107  {
1108  //Perform lexicographic comparison
1109  if(nextEntry == NULL)
1110  acceptable = TRUE;
1111  else if(strlen(entry->name) < strlen(nextEntry->name))
1112  acceptable = TRUE;
1113  else if(strlen(entry->name) > strlen(nextEntry->name))
1114  acceptable = FALSE;
1115  else if(strcmp(entry->name, nextEntry->name) < 0)
1116  acceptable = TRUE;
1117  else
1118  acceptable = FALSE;
1119 
1120  //Save the closest object identifier that follows the specified
1121  //OID in lexicographic order
1122  if(acceptable)
1123  nextEntry = entry;
1124  }
1125  }
1126  }
1127 
1128  //The specified OID does not lexicographically precede the name
1129  //of some object?
1130  if(nextEntry == NULL)
1131  return ERROR_OBJECT_NOT_FOUND;
1132 
1133  //Append the instance identifier to the OID prefix
1134  n = object->oidLen;
1135 
1136  //usmUserEngineID is used as 1st instance identifier
1137  error = mibEncodeOctetString(nextOid, *nextOidLen, &n,
1138  context->contextEngine, context->contextEngineLen, FALSE);
1139  //Any error to report?
1140  if(error)
1141  return error;
1142 
1143  //usmUserName is used as 2nd instance identifier
1144  error = mibEncodeString(nextOid, *nextOidLen, &n, nextEntry->name, FALSE);
1145  //Any error to report?
1146  if(error)
1147  return error;
1148 
1149  //Save the length of the resulting object identifier
1150  *nextOidLen = n;
1151  //Next object found
1152  return NO_ERROR;
1153 }
1154 
1155 #endif
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
int bool_t
Definition: compiler_port.h:49
uint8_t publicValue[SNMP_MAX_PUBLIC_VALUE_SIZE]
Public value.
SnmpKey localizedPrivKey
Localized privacy key.
SnmpAccess mode
Access mode.
OID (Object Identifier)
const uint8_t usmHMAC384SHA512AuthProtocolOid[9]
#define SNMP_AGENT_MAX_USERS
Definition: snmp_agent.h:83
#define TRUE
Definition: os_port.h:50
SnmpUserEntry tempUser
size_t digestSize
Definition: crypto.h:1135
__start_packed struct @205 MibVariant
Variant data type.
User-based security model.
User table entry.
const uint8_t usmUserEntryOid[10]
int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2, size_t oidLen2)
Compare object identifiers.
Definition: oid.c:101
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.
error_t
Error codes.
Definition: error.h:42
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]
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]
uint8_t oid[1]
Definition: mib_common.h:186
const uint8_t usmHMAC256SHA384AuthProtocolOid[9]
#define TRACE_INFO(...)
Definition: debug.h:94
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.
int32_t netGetRandRange(int32_t min, int32_t max)
Get a random value in the specified range.
Definition: net.c:1841
SNMP secret key.
char char_t
Definition: compiler_port.h:43
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:100
Common definitions for MIB modules.
uint8_t n
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
SnmpKey rawAuthKey
Raw authentication key.
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.
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:1128
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:941
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
uint8_t value[]
Definition: dtls_misc.h:150
unsigned int uint_t
Definition: compiler_port.h:45
SnmpAgentContext * context
TCP/IP stack core.
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
SnmpKey rawPrivKey
Raw privacy key.
const uint8_t usmDESPrivProtocolOid[9]
Success.
Definition: error.h:44
void snmpUsmMibLock(void)
Lock SNMP USM MIB base.
Debugging facilities.
ASN.1 (Abstract Syntax Notation One)