oid.c
Go to the documentation of this file.
1 /**
2  * @file oid.c
3  * @brief OID (Object Identifier)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO 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.6.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "encoding/oid.h"
37 #include "debug.h"
38 
39 //Check crypto library configuration
40 #if (OID_SUPPORT == ENABLED)
41 
42 
43 /**
44  * @brief Check whether the specified object identifier is valid
45  * @param[in] oid Pointer to the object identifier
46  * @param[in] oidLen Length of the OID, in bytes
47  * @return Error code
48  **/
49 
50 error_t oidCheck(const uint8_t *oid, size_t oidLen)
51 {
52  size_t i;
53  size_t n;
54 
55  //Check parameters
56  if(oid == NULL)
58 
59  //Check the length of the OID
60  if(oidLen == 0)
61  {
62  //Report an error
63  return ERROR_INVALID_SYNTAX;
64  }
65  else if(oidLen > 1)
66  {
67  //Parse the object identifier
68  for(i = 1, n = 2; i < oidLen; i++)
69  {
70  //Update the total number of nodes
71  if((oid[i] & OID_MORE_FLAG) == 0)
72  {
73  n++;
74  }
75 
76  //SNMP limits object identifier values to a maximum of 128 nodes
77  if(n > 128)
78  return ERROR_INVALID_SYNTAX;
79  }
80 
81  //Ensure that the last sub-identifier is valid
82  if(oid[oidLen - 1] & OID_MORE_FLAG)
83  return ERROR_INVALID_SYNTAX;
84  }
85 
86  //The specified OID is valid
87  return NO_ERROR;
88 }
89 
90 
91 /**
92  * @brief Compare object identifiers
93  * @param[in] oid1 Pointer the first OID
94  * @param[in] oidLen1 Length of the first OID, in bytes
95  * @param[in] oid2 Pointer the second OID
96  * @param[in] oidLen2 Length of the second OID, in bytes
97  * @return Comparison result
98  * @retval 0 Objects identifiers are equal
99  * @retval -1 The first OID lexicographically precedes the second OID
100  * @retval 1 The second OID lexicographically precedes the first OID
101  **/
102 
103 int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2,
104  size_t oidLen2)
105 {
106  int_t res;
107  size_t n1;
108  size_t n2;
109  size_t pos1;
110  size_t pos2;
111  bool_t more1;
112  bool_t more2;
113 
114  //Initialize variables
115  res = 0;
116  n1 = 0;
117  n2 = 0;
118  pos1 = 0;
119  pos2 = 0;
120  more1 = TRUE;
121  more2 = TRUE;
122 
123  //Perform lexicographical comparison
124  while(res == 0)
125  {
126  //Extract sub-identifier from first OID
127  if(more1)
128  {
129  if(pos1 >= oidLen1)
130  {
131  more1 = FALSE;
132  }
133  else if(pos1 == 0)
134  {
135  pos1++;
136  n1++;
137  more1 = FALSE;
138  }
139  else if(n1 == 0 && oid1[pos1] == OID_MORE_FLAG)
140  {
141  pos1++;
142  }
143  else if((oid1[pos1] & OID_MORE_FLAG) != 0)
144  {
145  pos1++;
146  n1++;
147  }
148  else
149  {
150  pos1++;
151  n1++;
152  more1 = FALSE;
153  }
154  }
155 
156  //Extract sub-identifier from second OID
157  if(more2)
158  {
159  if(pos2 >= oidLen2)
160  {
161  more2 = FALSE;
162  }
163  else if(pos2 == 0)
164  {
165  pos2++;
166  n2++;
167  more2 = FALSE;
168  }
169  else if(n2 == 0 && oid2[pos2] == OID_MORE_FLAG)
170  {
171  pos2++;
172  }
173  else if((oid2[pos2] & OID_MORE_FLAG) != 0)
174  {
175  pos2++;
176  n2++;
177  }
178  else
179  {
180  pos2++;
181  n2++;
182  more2 = FALSE;
183  }
184  }
185 
186  //Compare sub-identifiers
187  if(!more1 && !more2)
188  {
189  //Check the length of the sub-identifiers
190  if(n1 == 0 && n2 == 0)
191  {
192  res = 0;
193  break;
194  }
195  else if(n1 < n2)
196  {
197  res = -1;
198  }
199  else if(n1 > n2)
200  {
201  res = 1;
202  }
203  else
204  {
205  //Compare sub-identifier values
206  res = osMemcmp(oid1 + pos1 - n1, oid2 + pos2 - n2, n1);
207 
208  //Check comparison result
209  if(res < 0)
210  {
211  res = -1;
212  }
213  else if(res > 0)
214  {
215  res = 1;
216  }
217  else
218  {
219  //Decode next sub-identifiers
220  n1 = 0;
221  n2 = 0;
222  more1 = TRUE;
223  more2 = TRUE;
224  }
225  }
226  }
227  }
228 
229  //Return comparison result
230  return res;
231 }
232 
233 
234 /**
235  * @brief Check whether an OID matches the specified subtree
236  * @param[in] oid Pointer to the object identifier
237  * @param[in] oidLen Length of the OID, in bytes
238  * @param[in] subtree Pointer to the subtree
239  * @param[in] subtreeLen Length of the subtree, in bytes
240  * @param[in] mask Pointer to the mask
241  * @param[in] maskLen Length of the mask, in bytes
242  * @return TRUE if the OID matches the specified subtree, else FALSE
243  **/
244 
245 bool_t oidMatch(const uint8_t *oid, size_t oidLen, const uint8_t *subtree,
246  size_t subtreeLen, const uint8_t *mask, size_t maskLen)
247 {
248  size_t i;
249  uint8_t flag;
250  size_t oidPos;
251  size_t subtreePos;
252 
253  //Initialize variables
254  oidPos = 0;
255  subtreePos = 0;
256 
257  //Check whether the OID matches the specified subtree
258  for(i = 0; subtreePos < subtreeLen; i++)
259  {
260  //Check the length of the OID
261  if(oidPos >= oidLen)
262  return FALSE;
263 
264  //The bit mask is extended with 1's to be the required length
265  if((i / 8) < maskLen)
266  {
267  flag = mask[i / 8] & (1U << (7 - (i % 8)));
268  }
269  else
270  {
271  flag = 1;
272  }
273 
274  //First node?
275  if(i == 0)
276  {
277  //The mask allows for a simple form of wildcarding
278  if(flag)
279  {
280  //Compare the first sub-identifier
281  if((oid[0] / 40) != (subtree[0] / 40))
282  return FALSE;
283  }
284  }
285  //Second node?
286  else if(i == 1)
287  {
288  //The mask allows for a simple form of wildcarding
289  if(flag)
290  {
291  //Compare the second sub-identifier
292  if((oid[0] % 40) != (subtree[0] % 40))
293  return FALSE;
294  }
295 
296  //Jump to the next node
297  oidPos = 1;
298  subtreePos = 1;
299  }
300  //Remaining nodes?
301  else
302  {
303  //The mask allows for a simple form of wildcarding
304  if(flag)
305  {
306  //Compare sub-identifiers
307  while(1)
308  {
309  //Compare the current byte
310  if(oid[oidPos] != subtree[subtreePos])
311  return FALSE;
312 
313  //Bit b8 is set to zero to indicate the last byte
314  flag = oid[oidPos] & OID_MORE_FLAG;
315 
316  //Next byte
317  oidPos++;
318  subtreePos++;
319 
320  //Last byte of the sub-identifier?
321  if(!flag)
322  break;
323 
324  //Check the length of the OID
325  if(oidPos >= oidLen)
326  return FALSE;
327 
328  //Check the length of the subtree
329  if(subtreePos > subtreeLen)
330  return FALSE;
331  }
332  }
333  else
334  {
335  //Read the OID until the last byte of the sub-identifier is found
336  while(1)
337  {
338  //Bit b8 is set to zero to indicate the last byte
339  flag = oid[oidPos] & OID_MORE_FLAG;
340 
341  //Next byte
342  oidPos++;
343 
344  //Last byte of the sub-identifier?
345  if(!flag)
346  break;
347 
348  //Check the length of the OID
349  if(oidPos >= oidLen)
350  return FALSE;
351  }
352 
353  //Read the subtree until the last byte of the sub-identifier is found
354  while(1)
355  {
356  //Bit b8 is set to zero to indicate the last byte
357  flag = subtree[subtreePos] & OID_MORE_FLAG;
358 
359  //Next byte
360  subtreePos++;
361 
362  //Last byte of the sub-identifier?
363  if(!flag)
364  break;
365 
366  //Check the length of the subtree
367  if(subtreePos >= subtreeLen)
368  return FALSE;
369  }
370  }
371  }
372  }
373 
374  //The OID matches the specified subtree
375  return TRUE;
376 }
377 
378 
379 /**
380  * @brief Calculate the number of sub-identifiers
381  * @param[in] oid Pointer to the object identifier
382  * @param[in] oidLen Length of the OID, in bytes
383  * @return Number of sub-identifiers
384  **/
385 
386 uint_t oidCountSubIdentifiers(const uint8_t *oid, size_t oidLen)
387 {
388  size_t i;
389  uint_t n;
390 
391  //Check the length of the OID
392  if(oidLen == 0)
393  {
394  //The OID is empty
395  n = 0;
396  }
397  else
398  {
399  //The first byte encodes two sub-identifiers
400  n = 2;
401 
402  //Parse the object identifier
403  for(i = 1; i < oidLen; i++)
404  {
405  //Update the total number of sub-identifiers
406  if((oid[i] & OID_MORE_FLAG) == 0)
407  {
408  n++;
409  }
410  }
411  }
412 
413  //Return the total number of sub-identifiers
414  return n;
415 }
416 
417 
418 /**
419  * @brief Encode OID sub-identifier
420  * @param[in] oid Pointer to the object identifier
421  * @param[in] maxOidLen Maximum number of bytes the OID can hold
422  * @param[in,out] pos Offset where to write the sub-identifier
423  * @param[in] value Value of the sub-identifier
424  * @return Error code
425  **/
426 
427 error_t oidEncodeSubIdentifier(uint8_t *oid, size_t maxOidLen,
428  size_t *pos, uint32_t value)
429 {
430  size_t i;
431  size_t n;
432  uint8_t temp[5];
433 
434  //Encode the first byte of the sub-identifier
435  temp[0] = value & OID_VALUE_MASK;
436  //Shift the value to the right
437  value >>= 7;
438 
439  //Encode the remaining bytes
440  for(n = 1; value != 0; n++)
441  {
442  //Encode current byte
443  temp[n] = OID_MORE_FLAG | (value & OID_VALUE_MASK);
444  //Shift the value to the right
445  value >>= 7;
446  }
447 
448  //Sanity check
449  if((*pos + n) > maxOidLen)
450  return ERROR_BUFFER_OVERFLOW;
451 
452  //Write the current sub-identifier
453  for(i = 0; i < n; i++)
454  {
455  oid[*pos + i] = temp[n - i - 1];
456  }
457 
458  //Update offset value
459  *pos += n;
460 
461  //Successful processing
462  return NO_ERROR;
463 }
464 
465 
466 /**
467  * @brief Decode OID sub-identifier
468  * @param[in] oid Pointer to the object identifier
469  * @param[in] oidLen Length of the OID, in bytes
470  * @param[in,out] pos Offset where to read the sub-identifier
471  * @param[out] value Value of the sub-identifier
472  * @return Error code
473  **/
474 
475 error_t oidDecodeSubIdentifier(const uint8_t *oid, size_t oidLen,
476  size_t *pos, uint32_t *value)
477 {
478  size_t i;
479 
480  //Initialize the value of the sub-identifier
481  *value = 0;
482 
483  //Sanity check
484  if(*pos >= oidLen)
486 
487  //Read the OID until the last byte of the sub-identifier is found
488  for(i = *pos; i < oidLen; i++)
489  {
490  //Shift the value to the left
491  *value <<= 7;
492  //Update value of the sub-identifier
493  *value |= oid[i] & OID_VALUE_MASK;
494 
495  //Bit b8 is set to zero to indicate the last byte
496  if((oid[i] & OID_MORE_FLAG) == 0)
497  {
498  //Update offset value
499  *pos = i + 1;
500  //Successful processing
501  return NO_ERROR;
502  }
503  }
504 
505  //The specified OID is not valid
506  return ERROR_INVALID_SYNTAX;
507 }
508 
509 
510 /**
511  * @brief Convert a string representation of an OID to a binary OID
512  * @param[in] str NULL-terminated string representing the OID
513  * @param[out] oid Object identifier
514  * @param[in] maxOidLen Maximum number of bytes the OID can hold
515  * @param[out] oidLen Length of the object identifier
516  * @return Error code
517  **/
518 
519 error_t oidFromString(const char_t *str, uint8_t *oid, size_t maxOidLen,
520  size_t *oidLen)
521 {
522  error_t error;
523  size_t i;
524  size_t j;
525  size_t n;
526  uint32_t value;
527  uint8_t temp[5];
528 
529  //Reset the length of the OID
530  *oidLen = 0;
531 
532  //Number of nodes
533  i = 0;
534  //Initialize the value of the sub-identifier
535  value = 0;
536 
537  //Parse input string
538  while(1)
539  {
540  //Digit found?
541  if(osIsdigit(*str))
542  {
543  //Update the value of the sub-identifier
544  value = (value * 10) + (*str - '0');
545  }
546  //Separator or end of string found?
547  else if(*str == '.' || *str == '\0')
548  {
549  //First node?
550  if(i == 0)
551  {
552  //Check value
553  if(value > 6)
554  {
555  //The conversion failed
556  error = ERROR_INVALID_SYNTAX;
557  break;
558  }
559 
560  //Encode the first sub-identifier
561  temp[0] = value * 40;
562  //Prepare to decode the next node
563  value = 0;
564  //Do not write current sub-identifier yet
565  n = 0;
566  }
567  //Second node?
568  else if(i == 1)
569  {
570  //Check value
571  if(value > 39)
572  {
573  //The conversion failed
574  error = ERROR_INVALID_SYNTAX;
575  break;
576  }
577 
578  //Encode the second sub-identifier
579  temp[0] += value;
580  //Prepare to decode the next node
581  value = 0;
582  //Write the first two sub-identifiers
583  n = 1;
584  }
585  //Remaining nodes?
586  else
587  {
588  //Encode the first byte of the sub-identifier
589  temp[0] = value & OID_VALUE_MASK;
590  //Shift the value to the right
591  value >>= 7;
592 
593  //Encode the remaining bytes
594  for(n = 1; value != 0; n++)
595  {
596  //Encode current byte
597  temp[n] = OID_MORE_FLAG | (value & OID_VALUE_MASK);
598  //Shift the value to the right
599  value >>= 7;
600  }
601  }
602 
603  //Sanity check
604  if(n > maxOidLen)
605  {
606  //Report an error
607  error = ERROR_BUFFER_OVERFLOW;
608  break;
609  }
610 
611  //Write the current sub-identifier
612  for(j = 0; j < n; j++)
613  {
614  oid[j] = temp[n - j - 1];
615  }
616 
617  //Advance write pointer
618  oid += n;
619  *oidLen += n;
620  maxOidLen -= n;
621 
622  //Number of sub-identifiers
623  i++;
624 
625  //End of string detected?
626  if(*str == '\0')
627  {
628  //The conversion succeeded
629  error = NO_ERROR;
630  break;
631  }
632  }
633  //Invalid character...
634  else
635  {
636  //The conversion failed
637  error = ERROR_INVALID_SYNTAX;
638  break;
639  }
640 
641  //Point to the next character
642  str++;
643  }
644 
645  //Return status code
646  return error;
647 }
648 
649 
650 /**
651  * @brief Convert a binary OID to a string representation
652  * @param[in] oid Object identifier
653  * @param[in] oidLen Length of the object identifier, in bytes
654  * @param[out] str NULL-terminated string representing the OID
655  * @param[in] maxStrLen Maximum length of the resulting string
656  * @return Pointer to the formatted string
657  **/
658 
659 char_t *oidToString(const uint8_t *oid, size_t oidLen, char_t *str,
660  size_t maxStrLen)
661 {
662  static char_t buffer[128];
663  size_t i;
664  size_t n;
665  uint32_t value;
666  char_t *p;
667  char_t temp[12];
668 
669  //The str parameter is optional
670  if(str == NULL)
671  {
672  //Point to the internal buffer
673  str = buffer;
674  //Maximum length of the resulting string
675  maxStrLen = sizeof(buffer) - 1;
676  }
677 
678  //Point to the beginning of the string
679  p = str;
680  //Properly terminate the string
681  *p = '\0';
682 
683  //Check the length of the OID
684  if(oidLen > 0)
685  {
686  //Convert the first 2 bytes
687  n = osSprintf(temp, "%" PRIu8 ".%" PRIu8 "", (uint8_t) (oid[0] / 40),
688  (uint8_t) (oid[0] % 40));
689 
690  //Sanity check
691  if(n <= maxStrLen)
692  {
693  //Copy the resulting string
694  osStrcpy(p, temp);
695  //Advance write pointer
696  p += n;
697  maxStrLen -= n;
698  }
699 
700  //Initialize the value of the sub-identifier
701  value = 0;
702 
703  //Convert the rest of the OID
704  for(i = 1; i < oidLen; i++)
705  {
706  //Shift the value to the left
707  value <<= 7;
708  //Update the current value
709  value |= oid[i] & OID_VALUE_MASK;
710 
711  //Bit b8 is set to zero to indicate the last byte
712  if((oid[i] & OID_MORE_FLAG) == 0)
713  {
714  //Dump current value
715  n = osSprintf(temp, ".%" PRIu32, value);
716 
717  //Sanity check
718  if(n <= maxStrLen)
719  {
720  //Copy the resulting string
721  osStrcpy(p, temp);
722  //Advance write pointer
723  p += n;
724  maxStrLen -= n;
725  }
726 
727  //Prepare to decode the next value
728  value = 0;
729  }
730  }
731  }
732 
733  //Return a pointer to the formatted string
734  return str;
735 }
736 
737 
738 /**
739  * @brief Convert a bit mask to binary representation
740  * @param[in] str NULL-terminated string representing the bit mask
741  * @param[out] mask Pointer to the buffer where to store the resulting mask
742  * @param[in] maxMaskLen Maximum number of bytes the buffer can hold
743  * @param[out] maskLen Length of the mask
744  * @return Error code
745  **/
746 
747 error_t maskFromString(const char_t *str, uint8_t *mask, size_t maxMaskLen,
748  size_t *maskLen)
749 {
750  error_t error;
751  size_t i;
752  size_t j;
753 
754  //Point to the first byte
755  i = 0;
756  //Point to the most-significant bit
757  j = 8;
758 
759  //Parse input string
760  while(1)
761  {
762  //Check current character
763  if(*str == '0' || *str == '1')
764  {
765  //Make sure the output buffer is large enough
766  if(i >= maxMaskLen)
767  {
768  //Report an error
769  error = ERROR_BUFFER_OVERFLOW;
770  break;
771  }
772 
773  //Update bit mask
774  if(*str == '1')
775  {
776  mask[i] |= (1U << (j - 1));
777  }
778  else
779  {
780  mask[i] &= ~(1U << (j - 1));
781  }
782 
783  //Next bit
784  j--;
785  }
786  else if(*str == '\0')
787  {
788  //End of string detected
789  error = NO_ERROR;
790  break;
791  }
792  else
793  {
794  //Discard any other characters
795  }
796 
797  //Check whether the least-significant bit has been reached
798  if(j == 0)
799  {
800  //Point to the most-significant bit of the next byte
801  j = 8;
802  i++;
803  }
804 
805  //Point to the next character
806  str++;
807  }
808 
809  //Check status code
810  if(!error)
811  {
812  //Incomplete byte?
813  if(j < 8)
814  {
815  //The bit mask is extended with 1's to be the required length
816  mask[i] |= (1U << j) - 1;
817  //Save the length of the resulting mask
818  *maskLen = i + 1;
819  }
820  else
821  {
822  //Save the length of the resulting mask
823  *maskLen = i;
824  }
825  }
826 
827  //Return status code
828  return error;
829 }
830 
831 #endif
int bool_t
Definition: compiler_port.h:63
signed int int_t
Definition: compiler_port.h:56
error_t maskFromString(const char_t *str, uint8_t *mask, size_t maxMaskLen, size_t *maskLen)
Convert a bit mask to binary representation.
Definition: oid.c:747
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:143
error_t oidFromString(const char_t *str, uint8_t *oid, size_t maxOidLen, size_t *oidLen)
Convert a string representation of an OID to a binary OID.
Definition: oid.c:519
OID (Object Identifier)
uint8_t p
Definition: ndp.h:300
#define TRUE
Definition: os_port.h:50
#define osMemcmp(p1, p2, length)
Definition: os_port.h:156
const uint8_t res[]
error_t oidEncodeSubIdentifier(uint8_t *oid, size_t maxOidLen, size_t *pos, uint32_t value)
Encode OID sub-identifier.
Definition: oid.c:427
int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2, size_t oidLen2)
Compare object identifiers.
Definition: oid.c:103
uint8_t oid[]
Definition: lldp_tlv.h:300
error_t oidDecodeSubIdentifier(const uint8_t *oid, size_t oidLen, size_t *pos, uint32_t *value)
Decode OID sub-identifier.
Definition: oid.c:475
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define OID_MORE_FLAG
Definition: oid.h:38
error_t
Error codes.
Definition: error.h:43
@ ERROR_INSTANCE_NOT_FOUND
Definition: error.h:258
#define osSprintf(dest,...)
Definition: os_port.h:234
bool_t oidMatch(const uint8_t *oid, size_t oidLen, const uint8_t *subtree, size_t subtreeLen, const uint8_t *mask, size_t maskLen)
Check whether an OID matches the specified subtree.
Definition: oid.c:245
General definitions for cryptographic algorithms.
uint8_t mask
Definition: web_socket.h:319
#define osIsdigit(c)
Definition: os_port.h:288
char char_t
Definition: compiler_port.h:55
error_t oidCheck(const uint8_t *oid, size_t oidLen)
Check whether the specified object identifier is valid.
Definition: oid.c:50
uint_t oidCountSubIdentifiers(const uint8_t *oid, size_t oidLen)
Calculate the number of sub-identifiers.
Definition: oid.c:386
uint8_t n
char_t * oidToString(const uint8_t *oid, size_t oidLen, char_t *str, size_t maxStrLen)
Convert a binary OID to a string representation.
Definition: oid.c:659
#define OID_VALUE_MASK
Definition: oid.h:39
uint8_t value[]
Definition: tcp.h:376
uint8_t oidLen
Definition: lldp_tlv.h:299
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
unsigned int uint_t
Definition: compiler_port.h:57
#define osStrcpy(s1, s2)
Definition: os_port.h:210
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.