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-2024 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.4.4
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 "", oid[0] / 40, oid[0] % 40);
688 
689  //Sanity check
690  if(n <= maxStrLen)
691  {
692  //Copy the resulting string
693  osStrcpy(p, temp);
694  //Advance write pointer
695  p += n;
696  maxStrLen -= n;
697  }
698 
699  //Initialize the value of the sub-identifier
700  value = 0;
701 
702  //Convert the rest of the OID
703  for(i = 1; i < oidLen; i++)
704  {
705  //Shift the value to the left
706  value <<= 7;
707  //Update the current value
708  value |= oid[i] & OID_VALUE_MASK;
709 
710  //Bit b8 is set to zero to indicate the last byte
711  if((oid[i] & OID_MORE_FLAG) == 0)
712  {
713  //Dump current value
714  n = osSprintf(temp, ".%" PRIu32, value);
715 
716  //Sanity check
717  if(n <= maxStrLen)
718  {
719  //Copy the resulting string
720  osStrcpy(p, temp);
721  //Advance write pointer
722  p += n;
723  maxStrLen -= n;
724  }
725 
726  //Prepare to decode the next value
727  value = 0;
728  }
729  }
730  }
731 
732  //Return a pointer to the formatted string
733  return str;
734 }
735 
736 
737 /**
738  * @brief Convert a bit mask to binary representation
739  * @param[in] str NULL-terminated string representing the bit mask
740  * @param[out] mask Pointer to the buffer where to store the resulting mask
741  * @param[in] maxMaskLen Maximum number of bytes the buffer can hold
742  * @param[out] maskLen Length of the mask
743  * @return Error code
744  **/
745 
746 error_t maskFromString(const char_t *str, uint8_t *mask, size_t maxMaskLen,
747  size_t *maskLen)
748 {
749  error_t error;
750  size_t i;
751  size_t j;
752 
753  //Point to the first byte
754  i = 0;
755  //Point to the most-significant bit
756  j = 8;
757 
758  //Parse input string
759  while(1)
760  {
761  //Check current character
762  if(*str == '0' || *str == '1')
763  {
764  //Make sure the output buffer is large enough
765  if(i >= maxMaskLen)
766  {
767  //Report an error
768  error = ERROR_BUFFER_OVERFLOW;
769  break;
770  }
771 
772  //Update bit mask
773  if(*str == '1')
774  {
775  mask[i] |= (1U << (j - 1));
776  }
777  else
778  {
779  mask[i] &= ~(1U << (j - 1));
780  }
781 
782  //Next bit
783  j--;
784  }
785  else if(*str == '\0')
786  {
787  //End of string detected
788  error = NO_ERROR;
789  break;
790  }
791  else
792  {
793  //Discard any other characters
794  }
795 
796  //Check whether the least-significant bit has been reached
797  if(j == 0)
798  {
799  //Point to the most-significant bit of the next byte
800  j = 8;
801  i++;
802  }
803 
804  //Point to the next character
805  str++;
806  }
807 
808  //Check status code
809  if(!error)
810  {
811  //Incomplete byte?
812  if(j < 8)
813  {
814  //The bit mask is extended with 1's to be the required length
815  mask[i] |= (1U << j) - 1;
816  //Save the length of the resulting mask
817  *maskLen = i + 1;
818  }
819  else
820  {
821  //Save the length of the resulting mask
822  *maskLen = i;
823  }
824  }
825 
826  //Return status code
827  return error;
828 }
829 
830 #endif
int bool_t
Definition: compiler_port.h:53
signed int int_t
Definition: compiler_port.h:49
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:746
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
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:153
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:257
#define osSprintf(dest,...)
Definition: os_port.h:231
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:285
char char_t
Definition: compiler_port.h:48
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:369
uint8_t oidLen
Definition: lldp_tlv.h:299
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
unsigned int uint_t
Definition: compiler_port.h:50
#define osStrcpy(s1, s2)
Definition: os_port.h:207
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.