asn1.c
Go to the documentation of this file.
1 /**
2  * @file asn1.c
3  * @brief ASN.1 (Abstract Syntax Notation One)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 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.5.0
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/asn1.h"
37 #include "encoding/oid.h"
38 #include "debug.h"
39 
40 //Check crypto library configuration
41 #if (ASN1_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Read an ASN.1 tag from the input stream
46  * @param[in] data Input stream where to read the tag
47  * @param[in] length Number of bytes available in the input stream
48  * @param[out] tag Structure describing the ASN.1 tag
49  * @return Error code
50  **/
51 
52 error_t asn1ReadTag(const uint8_t *data, size_t length, Asn1Tag *tag)
53 {
54  uint_t i;
55  uint_t n;
56 
57  //Make sure the identifier octet is present
58  if(length == 0)
59  return ERROR_INVALID_TAG;
60 
61  //Save the class of the ASN.1 tag
62  tag->objClass = data[0] & ASN1_CLASS_MASK;
63  //Primitive or constructed encoding?
65 
66  //Check the tag number
67  if((data[0] & ASN1_TAG_NUMBER_MASK) < 31)
68  {
69  //Tag number is in the range 0 to 30
70  tag->objType = data[0] & ASN1_TAG_NUMBER_MASK;
71  //Point to the tag length field
72  i = 1;
73  }
74  else
75  {
76  //If the tag number is greater than or equal to 31,
77  //the subsequent octets will encode the tag number
78  tag->objType = 0;
79 
80  //Decode the tag number
81  for(i = 1; ; i++)
82  {
83  //The field cannot exceed 5 bytes
84  if(i > (sizeof(tag->objType) + 1))
85  return ERROR_INVALID_TAG;
86  //Insufficient number of bytes to decode the tag number?
87  if(!(length - i))
88  return ERROR_INVALID_TAG;
89 
90  //Update the tag number with bits 7 to 1
91  tag->objType = (tag->objType << 7) | (data[i] & 0x7F);
92 
93  //Bit 8 shall be set unless it is the last octet
94  if(!(data[i] & 0x80))
95  break;
96  }
97  //Point to the tag length field
98  i++;
99  }
100 
101  //Insufficient number of bytes to decode the tag length?
102  if(!(length - i))
103  return ERROR_INVALID_TAG;
104 
105  //Short form is used?
106  if(data[i] < 128)
107  {
108  //Bits 7 to 1 encode the number of bytes in the contents
109  tag->length = data[i];
110  //Point to the contents of the tag
111  i++;
112  }
113  //Long form is used?
114  else if(data[i] > 128 && data[i] < 255)
115  {
116  //Bits 7 to 1 encode the number of octets in the length field
117  n = data[i] & 0x7F;
118 
119  //The field cannot exceed 4 bytes
120  if(n > sizeof(tag->length))
121  return ERROR_INVALID_TAG;
122  //Insufficient number of bytes to decode the tag length?
123  if((length - i) < n)
124  return ERROR_INVALID_TAG;
125 
126  //Clear the tag length
127  tag->length = 0;
128 
129  //Read the subsequent octets
130  for(i++; n > 0; n--)
131  {
132  tag->length = (tag->length << 8) | data[i++];
133  }
134  }
135  //Indefinite form is used?
136  else
137  {
138  //Indefinite form is not supported
139  return ERROR_INVALID_TAG;
140  }
141 
142  //Save the pointer to the tag contents
143  tag->value = data + i;
144  //Check the length of tag
145  if((length - i) < tag->length)
146  return ERROR_INVALID_TAG;
147 
148  //Total length occupied by the ASN.1 tag in the input stream
149  tag->totalLength = i + tag->length;
150  //ASN.1 tag successfully decoded
151  return NO_ERROR;
152 }
153 
154 
155 /**
156  * @brief Read an ASN.1 sequence from the input stream
157  * @param[in] data Input stream where to read the tag
158  * @param[in] length Number of bytes available in the input stream
159  * @param[out] tag Structure describing the ASN.1 tag
160  * @return Error code
161  **/
162 
163 error_t asn1ReadSequence(const uint8_t *data, size_t length, Asn1Tag *tag)
164 {
165  error_t error;
166 
167  //Read ASN.1 tag
168  error = asn1ReadTag(data, length, tag);
169 
170  //Check status code
171  if(!error)
172  {
173  //Enforce encoding, class and type
175  }
176 
177  //Return status code
178  return error;
179 }
180 
181 
182 /**
183  * @brief Read an octet string from the input stream
184  * @param[in] data Input stream where to read the tag
185  * @param[in] length Number of bytes available in the input stream
186  * @param[out] tag Structure describing the ASN.1 tag
187  * @return Error code
188  **/
189 
190 error_t asn1ReadOctetString(const uint8_t *data, size_t length, Asn1Tag *tag)
191 {
192  error_t error;
193 
194  //Read ASN.1 tag
195  error = asn1ReadTag(data, length, tag);
196 
197  //Check status code
198  if(!error)
199  {
200  //Enforce encoding, class and type
203  }
204 
205  //Return status code
206  return error;
207 }
208 
209 
210 /**
211  * @brief Read an object identifier from the input stream
212  * @param[in] data Input stream where to read the tag
213  * @param[in] length Number of bytes available in the input stream
214  * @param[out] tag Structure describing the ASN.1 tag
215  * @return Error code
216  **/
217 
218 error_t asn1ReadOid(const uint8_t *data, size_t length, Asn1Tag *tag)
219 {
220  error_t error;
221 
222  //Read ASN.1 tag
223  error = asn1ReadTag(data, length, tag);
224 
225  //Check status code
226  if(!error)
227  {
228  //Enforce encoding, class and type
231  }
232 
233  //Return status code
234  return error;
235 }
236 
237 
238 /**
239  * @brief Read a boolean from the input stream
240  * @param[in] data Input stream where to read the tag
241  * @param[in] length Number of bytes available in the input stream
242  * @param[out] tag Structure describing the ASN.1 tag
243  * @param[out] value Boolean value
244  * @return Error code
245  **/
246 
247 error_t asn1ReadBoolean(const uint8_t *data, size_t length, Asn1Tag *tag,
248  bool_t *value)
249 {
250  error_t error;
251 
252  //Read ASN.1 tag
253  error = asn1ReadTag(data, length, tag);
254  //Failed to decode ASN.1 tag?
255  if(error)
256  return error;
257 
258  //Enforce encoding, class and type
260  //Invalid tag?
261  if(error)
262  return error;
263 
264  //Make sure the length of the boolean is valid
265  if(tag->length != 1)
266  return ERROR_INVALID_LENGTH;
267 
268  //Read the value of the boolean
269  *value = tag->value[0] ? TRUE : FALSE;
270 
271  //ASN.1 tag successfully decoded
272  return NO_ERROR;
273 }
274 
275 
276 /**
277  * @brief Read a 32-bit integer from the input stream
278  * @param[in] data Input stream where to read the tag
279  * @param[in] length Number of bytes available in the input stream
280  * @param[out] tag Structure describing the ASN.1 tag
281  * @param[out] value Integer value
282  * @return Error code
283  **/
284 
285 error_t asn1ReadInt32(const uint8_t *data, size_t length, Asn1Tag *tag,
286  int32_t *value)
287 {
288  error_t error;
289  size_t i;
290 
291  //Read ASN.1 tag
292  error = asn1ReadTag(data, length, tag);
293  //Failed to decode ASN.1 tag?
294  if(error)
295  return error;
296 
297  //Enforce encoding, class and type
299  //Invalid tag?
300  if(error)
301  return error;
302 
303  //The contents shall consist of one or more octets
304  if(tag->length < 1 || tag->length > 4)
305  return ERROR_INVALID_TAG;
306 
307  //The contents octets shall be a two's complement binary
308  //number equal to the integer value
309  *value = (tag->value[0] & 0x80) ? -1 : 0;
310 
311  //Process contents octets
312  for(i = 0; i < tag->length; i++)
313  {
314  //Rotate left operation
315  *value <<= 8;
316  //Reconstruct integer value
317  *value |= tag->value[i];
318  }
319 
320  //ASN.1 tag successfully decoded
321  return NO_ERROR;
322 }
323 
324 
325 /**
326  * @brief Write an ASN.1 tag
327  * @param[in] tag Structure describing the ASN.1 tag
328  * @param[in] reverse Use reverse encoding
329  * @param[out] data Output stream where to write the tag (optional parameter)
330  * @param[out] written Number of bytes written to the output stream (optional parameter)
331  * @return Error code
332  **/
333 
334 error_t asn1WriteTag(Asn1Tag *tag, bool_t reverse, uint8_t *data,
335  size_t *written)
336 {
337  size_t i;
338  size_t m;
339  size_t n;
340 
341  //Compute the number of octets that are necessary to encode the tag number
342  if(tag->objType < 31)
343  {
344  m = 0;
345  }
346  else if(tag->objType < 128)
347  {
348  m = 1;
349  }
350  else if(tag->objType < 16384)
351  {
352  m = 2;
353  }
354  else if(tag->objType < 2097152)
355  {
356  m = 3;
357  }
358  else if(tag->objType < 268435456)
359  {
360  m = 4;
361  }
362  else
363  {
364  m = 5;
365  }
366 
367  //Compute the number of octets that are necessary to encode the length field
368  if(tag->length < 128)
369  {
370  n = 0;
371  }
372  else if(tag->length < 256)
373  {
374  n = 1;
375  }
376  else if(tag->length < 65536)
377  {
378  n = 2;
379  }
380  else if(tag->length < 16777216)
381  {
382  n = 3;
383  }
384  else
385  {
386  n = 4;
387  }
388 
389  //Valid output stream?
390  if(data != NULL)
391  {
392  //Use reverse encoding?
393  if(reverse)
394  {
395  //Any data to copy?
396  if(tag->value != NULL && tag->length > 0)
397  {
398  //Make room for the data
399  data -= tag->length;
400  //Copy data
401  osMemmove(data, tag->value, tag->length);
402  }
403 
404  //Move backward
405  data -= m + n + 2;
406  }
407  else
408  {
409  //Any data to copy?
410  if(tag->value != NULL && tag->length > 0)
411  {
412  //Copy data
413  osMemmove(data + m + n + 2, tag->value, tag->length);
414  }
415  }
416 
417  //Save the class of the ASN.1 tag
418  data[0] = tag->objClass;
419 
420  //Primitive or constructed encoding?
421  if(tag->constructed)
422  {
424  }
425 
426  //Encode the tag number
427  if(m == 0)
428  {
429  //Tag number is in the range 0 to 30
430  data[0] |= tag->objType;
431  }
432  else
433  {
434  //The tag number is greater than or equal to 31
436 
437  //The subsequent octets will encode the tag number
438  for(i = 0; i < m; i++)
439  {
440  //Bits 7 to 1 encode the tag number
441  data[m - i] = (tag->objType >> (i * 7)) & 0x7F;
442 
443  //Bit 8 of each octet shall be set to one unless it is the
444  //last octet of the identifier octets
445  if(i != 0)
446  {
447  data[m - i] |= 0x80;
448  }
449  }
450  }
451 
452  //Encode the length field
453  if(n == 0)
454  {
455  //Use short form encoding
456  data[1 + m] = tag->length & 0x7F;
457  }
458  else
459  {
460  //Bits 7 to 1 encode the number of octets in the length field
461  data[1 + m] = 0x80 | (n & 0x7F);
462 
463  //The subsequent octets will encode the length field
464  for(i = 0; i < n; i++)
465  {
466  data[1 + m + n - i] = (tag->length >> (i * 8)) & 0xFF;
467  }
468  }
469  }
470 
471  //Total length occupied by the ASN.1 tag
472  tag->totalLength = tag->length + m + n + 2;
473 
474  //The last parameter is optional
475  if(written != NULL)
476  {
477  //Number of bytes written to the output stream
478  *written = m + n + 2;
479 
480  //Any data copied?
481  if(tag->value != NULL)
482  {
483  *written += tag->length;
484  }
485  }
486 
487  //Successful processing
488  return NO_ERROR;
489 }
490 
491 
492 /**
493  * @brief Write an ASN.1 tag header
494  * @param[in] tag Structure describing the ASN.1 tag
495  * @param[in] reverse Use reverse encoding
496  * @param[out] data Output stream where to write the tag (optional parameter)
497  * @param[out] written Number of bytes written to the output stream (optional parameter)
498  * @return Error code
499  **/
500 
501 
502 error_t asn1WriteHeader(Asn1Tag *tag, bool_t reverse, uint8_t *data,
503  size_t *written)
504 {
505  size_t i;
506  size_t m;
507  size_t n;
508 
509  //Compute the number of octets that are necessary to encode the tag number
510  if(tag->objType < 31)
511  {
512  m = 0;
513  }
514  else if(tag->objType < 128)
515  {
516  m = 1;
517  }
518  else if(tag->objType < 16384)
519  {
520  m = 2;
521  }
522  else if(tag->objType < 2097152)
523  {
524  m = 3;
525  }
526  else if(tag->objType < 268435456)
527  {
528  m = 4;
529  }
530  else
531  {
532  m = 5;
533  }
534 
535  //Compute the number of octets that are necessary to encode the length field
536  if(tag->length < 128)
537  {
538  n = 0;
539  }
540  else if(tag->length < 256)
541  {
542  n = 1;
543  }
544  else if(tag->length < 65536)
545  {
546  n = 2;
547  }
548  else if(tag->length < 16777216)
549  {
550  n = 3;
551  }
552  else
553  {
554  n = 4;
555  }
556 
557  //Valid output stream?
558  if(data != NULL)
559  {
560  //Use reverse encoding?
561  if(reverse)
562  {
563  //Move backward
564  data -= m + n + 2;
565  }
566 
567  //Save the class of the ASN.1 tag
568  data[0] = tag->objClass;
569 
570  //Primitive or constructed encoding?
571  if(tag->constructed)
572  {
574  }
575 
576  //Encode the tag number
577  if(m == 0)
578  {
579  //Tag number is in the range 0 to 30
580  data[0] |= tag->objType;
581  }
582  else
583  {
584  //The tag number is greater than or equal to 31
586 
587  //The subsequent octets will encode the tag number
588  for(i = 0; i < m; i++)
589  {
590  //Bits 7 to 1 encode the tag number
591  data[m - i] = (tag->objType >> (i * 7)) & 0x7F;
592 
593  //Bit 8 of each octet shall be set to one unless it is the
594  //last octet of the identifier octets
595  if(i != 0)
596  {
597  data[m - i] |= 0x80;
598  }
599  }
600  }
601 
602  //Encode the length field
603  if(n == 0)
604  {
605  //Use short form encoding
606  data[1 + m] = tag->length & 0x7F;
607  }
608  else
609  {
610  //Bits 7 to 1 encode the number of octets in the length field
611  data[1 + m] = 0x80 | (n & 0x7F);
612 
613  //The subsequent octets will encode the length field
614  for(i = 0; i < n; i++)
615  {
616  data[1 + m + n - i] = (tag->length >> (i * 8)) & 0xFF;
617  }
618  }
619  }
620 
621  //Total length occupied by the ASN.1 tag
622  tag->totalLength = tag->length + m + n + 2;
623 
624  //The last parameter is optional
625  if(written != NULL)
626  {
627  //Number of bytes written to the output stream
628  *written = m + n + 2;
629  }
630 
631  //Successful processing
632  return NO_ERROR;
633 }
634 
635 
636 /**
637  * @brief Write a 32-bit integer to the output stream
638  * @param[in] value Integer value
639  * @param[in] reverse Use reverse encoding
640  * @param[out] data Output stream where to write the tag (optional parameter)
641  * @param[out] written Number of bytes written to the output stream
642  * @return Error code
643  **/
644 
645 error_t asn1WriteInt32(int32_t value, bool_t reverse, uint8_t *data,
646  size_t *written)
647 {
648  size_t i;
649  size_t n;
650  uint16_t msb;
651 
652  //An integer value is always encoded in the smallest possible number of
653  //octets
654  for(n = 4; n > 1; n--)
655  {
656  //Retrieve the upper 9 bits
657  msb = (value >> (n * 8 - 9)) & 0x01FF;
658 
659  //The upper 9 bits shall not have the same value (all 0 or all 1)
660  if(msb != 0x0000 && msb != 0x01FF)
661  break;
662  }
663 
664  //Valid output stream?
665  if(data != NULL)
666  {
667  //Use reverse encoding?
668  if(reverse)
669  data -= n + 2;
670 
671  //Write tag type
673  //Write tag length
674  data[1] = n & 0xFF;
675 
676  //Write contents octets
677  for(i = 0; i < n; i++)
678  {
679  data[1 + n - i] = (value >> (i * 8)) & 0xFF;
680  }
681  }
682 
683  //Number of bytes written to the output stream
684  if(written != NULL)
685  *written = n + 2;
686 
687  //Successful processing
688  return NO_ERROR;
689 }
690 
691 
692 #if (MPI_SUPPORT == ENABLED)
693 
694 /**
695  * @brief Read a multiple-precision integer from the input stream
696  * @param[in] data Input stream where to read the tag
697  * @param[in] length Number of bytes available in the input stream
698  * @param[out] tag Structure describing the ASN.1 tag
699  * @param[out] value Integer value
700  * @return Error code
701  **/
702 
703 error_t asn1ReadMpi(const uint8_t *data, size_t length, Asn1Tag *tag,
704  Mpi *value)
705 {
706  error_t error;
707 
708  //Read ASN.1 tag
709  error = asn1ReadTag(data, length, tag);
710  //Failed to decode ASN.1 tag?
711  if(error)
712  return error;
713 
714  //Enforce encoding, class and type
716  //Invalid tag?
717  if(error)
718  return error;
719 
720  //Negative integer?
721  if(tag->length > 0 && (tag->value[0] & 0x80) != 0)
722  return ERROR_INVALID_SYNTAX;
723 
724  //Convert the octet string to a multiple precision integer
725  error = mpiImport(value, tag->value, tag->length, MPI_FORMAT_BIG_ENDIAN);
726 
727  //Return status code
728  return error;
729 }
730 
731 
732 /**
733  * @brief Write a multiple-precision integer from the output stream
734  * @param[in] value Integer value
735  * @param[in] reverse Use reverse encoding
736  * @param[out] data Output stream where to write the tag (optional parameter)
737  * @param[out] written Number of bytes written to the output stream
738  * @return Error code
739  **/
740 
741 error_t asn1WriteMpi(const Mpi *value, bool_t reverse, uint8_t *data,
742  size_t *written)
743 {
744  error_t error;
745  size_t n;
746  Asn1Tag tag;
747 
748  //Retrieve the length of the multiple precision integer
750 
751  //An integer value is always encoded in the smallest possible number of
752  //octets
753  n = (n / 8) + 1;
754 
755  //Valid output stream?
756  if(data != NULL)
757  {
758  //Use reverse encoding?
759  if(reverse)
760  data -= n;
761 
762  //The value of the multiple precision integer is encoded MSB first
764  //Any error to report?
765  if(error)
766  return error;
767  }
768 
769  //The integer is encapsulated within an ASN.1 structure
770  tag.constructed = FALSE;
773  tag.length = n;
774  tag.value = data;
775 
776  //Compute the length of the corresponding ASN.1 structure
777  error = asn1WriteTag(&tag, FALSE, data, NULL);
778  //Any error to report?
779  if(error)
780  return error;
781 
782  //Number of bytes written to the output stream
783  if(written != NULL)
784  *written = tag.totalLength;
785 
786  //Successful processing
787  return NO_ERROR;
788 }
789 
790 #endif
791 
792 
793 /**
794  * @brief Enforce the type of a specified tag
795  * @param[in] tag Pointer to an ASN.1 tag
796  * @param[in] constructed Expected encoding (TRUE for constructed, FALSE
797  * for primitive)
798  * @param[in] objClass Expected tag class
799  * @param[in] objType Expected tag type
800  * @return Error code
801  **/
802 
803 error_t asn1CheckTag(const Asn1Tag *tag, bool_t constructed, uint_t objClass,
804  uint_t objType)
805 {
806  //Check encoding
807  if(tag->constructed != constructed)
808  return ERROR_WRONG_ENCODING;
809  //Enforce class
810  if(tag->objClass != objClass)
811  return ERROR_INVALID_CLASS;
812  //Enforce type
813  if(tag->objType != objType)
814  return ERROR_INVALID_TYPE;
815 
816  //The tag matches all the criteria
817  return NO_ERROR;
818 }
819 
820 
821 /**
822  * @brief Check ASN.1 tag against a specified OID
823  * @param[in] tag Pointer to an ASN.1 tag
824  * @param[in] oid Expected object identifier (OID)
825  * @param[in] length Length of the OID
826  * @return Error code
827  **/
828 
829 error_t asn1CheckOid(const Asn1Tag *tag, const uint8_t *oid, size_t length)
830 {
831  error_t error;
832 
833  //Enforce encoding, class and type
835  //Any error to report?
836  if(error)
837  return error;
838 
839  //Compare OID against the specified value
840  if(oidComp(tag->value, tag->length, oid, length))
841  return ERROR_WRONG_IDENTIFIER;
842 
843  //The tag matches all the criteria
844  return NO_ERROR;
845 }
846 
847 
848 /**
849  * @brief Display an ASN.1 data object
850  * @param[in] data Pointer to the ASN.1 object to dump
851  * @param[in] length Length of the ASN.1 object
852  * @param[in] level Current level of recursion (this parameter shall be set to 0)
853  * @return Error code
854  **/
855 
856 error_t asn1DumpObject(const uint8_t *data, size_t length, uint_t level)
857 {
858 //Check debugging level
859 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
860  error_t error;
861  uint_t i;
862  Asn1Tag tag;
863 
864  //ASN.1 universal types
865  static const char_t *const label[32] =
866  {
867  "[0]",
868  "BOOLEAN",
869  "INTEGER",
870  "BIT STRING",
871  "OCTET STRING",
872  "NULL",
873  "OBJECT IDENTIFIER",
874  "OBJECT DESCRIPTOR",
875  "EXTERNAL",
876  "REAL",
877  "ENUMERATED",
878  "[11]",
879  "UTF8 STRING",
880  "[13]",
881  "[14]",
882  "[15]",
883  "SEQUENCE",
884  "SET",
885  "NUMERIC STRING",
886  "PRINTABLE STRING",
887  "TELETEX STRING",
888  "VIDEOTEX STRING",
889  "IA5 STRING",
890  "UTC TIME",
891  "GENERALIZED TIME",
892  "GRAPHIC STRING",
893  "VISIBLE STRING",
894  "GENERAL STRING",
895  "UNIVERSAL STRING",
896  "[29]",
897  "BMP STRING",
898  "[31]"
899  };
900 
901  //Prefix used to format the structure
902  static const char_t *const prefix[10] =
903  {
904  "",
905  " ",
906  " ",
907  " ",
908  " ",
909  " ",
910  " ",
911  " ",
912  " ",
913  " "
914  };
915 
916  //Parse ASN.1 object
917  while(length > 0)
918  {
919  //Decode current ASN.1 tag
920  error = asn1ReadTag(data, length, &tag);
921  //Decoding failed?
922  if(error)
923  return error;
924 
925  //Point to the next field
926  data += tag.totalLength;
927  length -= tag.totalLength;
928 
929  //Dump tag number, tag class, and contents length fields
930  if(tag.objType < 32 && (tag.objClass & ASN1_CLASS_MASK) == ASN1_CLASS_UNIVERSAL)
931  {
932  TRACE_DEBUG("%s%s (%" PRIuSIZE " bytes)\r\n", prefix[level], label[tag.objType], tag.length);
933  }
934  else
935  {
936  TRACE_DEBUG("%s[%u] (%" PRIuSIZE " bytes)\r\n", prefix[level], tag.objType, tag.length);
937  }
938 
939  //Constructed type?
940  if(tag.constructed)
941  {
942  //Check whether the maximum level of recursion is reached
943  if(level < 8)
944  {
945  //Recursive decoding of the ASN.1 tag
946  error = asn1DumpObject(tag.value, tag.length, level + 1);
947  //Decoding failed?
948  if(error)
949  return error;
950  }
951  else
952  {
953  //If the maximum level of recursion is reached, then dump contents
954  TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length);
955  }
956  }
957  else
958  {
959  //Universal tag?
961  {
962  //Check the type of the current tag
963  switch(tag.objType)
964  {
965  //OID?
967  //Append prefix
968  TRACE_DEBUG("%s", prefix[level + 1]);
969  //Print OID
970  TRACE_DEBUG("%s", oidToString(tag.value, tag.length, NULL, 0));
971  //Add a line feed
972  TRACE_DEBUG("\r\n");
973  break;
974 
975  //String?
987  //Append prefix
988  TRACE_DEBUG("%s", prefix[level + 1]);
989 
990  //Dump the entire string
991  for(i = 0; i < tag.length; i++)
992  {
993  TRACE_DEBUG("%c", tag.value[i]);
994  }
995 
996  //Add a line feed
997  TRACE_DEBUG("\r\n");
998  break;
999 
1000  //UTC time?
1001  case ASN1_TYPE_UTC_TIME:
1002  //Check length
1003  if(tag.length != 13)
1004  return ERROR_WRONG_ENCODING;
1005  //The encoding shall terminate with a "Z"
1006  if(tag.value[tag.length - 1] != 'Z')
1007  return ERROR_WRONG_ENCODING;
1008 
1009  //Append prefix
1010  TRACE_DEBUG("%s", prefix[level + 1]);
1011  //Display date
1012  TRACE_DEBUG("%c%c/%c%c/%c%c ", tag.value[0], tag.value[1],
1013  tag.value[2], tag.value[3], tag.value[4], tag.value[5]);
1014  //Display time
1015  TRACE_DEBUG("%c%c:%c%c:%c%c", tag.value[6], tag.value[7],
1016  tag.value[8], tag.value[9], tag.value[10], tag.value[11]);
1017  //Add a line feed
1018  TRACE_DEBUG("\r\n");
1019  break;
1020 
1021  //Generalized time?
1023  //Check length
1024  if(tag.length != 15)
1025  return ERROR_WRONG_ENCODING;
1026  //The encoding shall terminate with a "Z"
1027  if(tag.value[tag.length - 1] != 'Z')
1028  return ERROR_WRONG_ENCODING;
1029 
1030  //Append prefix
1031  TRACE_DEBUG("%s", prefix[level + 1]);
1032  //Display date
1033  TRACE_DEBUG("%c%c%c%c/%c%c/%c%c ", tag.value[0], tag.value[1], tag.value[2],
1034  tag.value[3], tag.value[4], tag.value[5], tag.value[6], tag.value[7]);
1035  //Display time
1036  TRACE_DEBUG("%c%c:%c%c:%c%c", tag.value[8], tag.value[9],
1037  tag.value[10], tag.value[11], tag.value[12], tag.value[13]);
1038  //Add a line feed
1039  TRACE_DEBUG("\r\n");
1040  break;
1041 
1042  //Any other type?
1043  default:
1044  //Dump the contents of the tag
1045  TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length);
1046  break;
1047  }
1048  }
1049  else
1050  {
1051  //Dump the contents of the tag
1052  TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length);
1053  }
1054  }
1055  }
1056 #endif
1057 
1058  //ASN.1 object successfully decoded
1059  return NO_ERROR;
1060 }
1061 
1062 #endif
@ ASN1_TYPE_UTC_TIME
Definition: asn1.h:87
@ ASN1_TYPE_GENERALIZED_TIME
Definition: asn1.h:88
int bool_t
Definition: compiler_port.h:61
Arbitrary precision integer.
Definition: mpi.h:102
@ ASN1_TYPE_VIDEOTEX_STRING
Definition: asn1.h:85
#define ASN1_CLASS_MASK
Definition: asn1.h:51
OID (Object Identifier)
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
error_t asn1WriteHeader(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written)
Write an ASN.1 tag header.
Definition: asn1.c:502
@ ASN1_TYPE_UTF8_STRING
Definition: asn1.h:79
error_t asn1ReadBoolean(const uint8_t *data, size_t length, Asn1Tag *tag, bool_t *value)
Read a boolean from the input stream.
Definition: asn1.c:247
error_t asn1DumpObject(const uint8_t *data, size_t length, uint_t level)
Display an ASN.1 data object.
Definition: asn1.c:856
@ ASN1_TYPE_IA5_STRING
Definition: asn1.h:86
error_t asn1ReadTag(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an ASN.1 tag from the input stream.
Definition: asn1.c:52
Ipv6Addr prefix
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
#define ASN1_ENCODING_CONSTRUCTED
Definition: asn1.h:48
error_t asn1ReadOid(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an object identifier from the input stream.
Definition: asn1.c:218
size_t totalLength
Definition: asn1.h:108
size_t length
Definition: asn1.h:106
#define FALSE
Definition: os_port.h:46
error_t asn1ReadOctetString(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an octet string from the input stream.
Definition: asn1.c:190
error_t
Error codes.
Definition: error.h:43
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:52
@ ASN1_TYPE_GRAPHIC_STRING
Definition: asn1.h:89
ASN.1 tag.
Definition: asn1.h:102
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:712
error_t asn1ReadInt32(const uint8_t *data, size_t length, Asn1Tag *tag, int32_t *value)
Read a 32-bit integer from the input stream.
Definition: asn1.c:285
@ ASN1_TYPE_UNIVERSAL_STRING
Definition: asn1.h:92
#define ASN1_TAG_NUMBER_MASK
Definition: asn1.h:43
@ ASN1_TYPE_VISIBLE_STRING
Definition: asn1.h:90
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
error_t asn1WriteMpi(const Mpi *value, bool_t reverse, uint8_t *data, size_t *written)
Write a multiple-precision integer from the output stream.
Definition: asn1.c:741
error_t asn1WriteTag(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written)
Write an ASN.1 tag.
Definition: asn1.c:334
@ ERROR_INVALID_TYPE
Definition: error.h:115
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:809
uint_t objClass
Definition: asn1.h:104
@ ASN1_TYPE_PRINTABLE_STRING
Definition: asn1.h:83
uint8_t length
Definition: tcp.h:375
error_t asn1CheckOid(const Asn1Tag *tag, const uint8_t *oid, size_t length)
Check ASN.1 tag against a specified OID.
Definition: asn1.c:829
@ ASN1_TYPE_TELETEX_STRING
Definition: asn1.h:84
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:254
@ ASN1_TYPE_OCTET_STRING
Definition: asn1.h:72
@ ASN1_TYPE_INTEGER
Definition: asn1.h:70
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
uint8_t m
Definition: ndp.h:304
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
error_t asn1ReadMpi(const uint8_t *data, size_t length, Asn1Tag *tag, Mpi *value)
Read a multiple-precision integer from the input stream.
Definition: asn1.c:703
uint8_t value[]
Definition: tcp.h:376
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:93
bool_t constructed
Definition: asn1.h:103
@ ERROR_WRONG_IDENTIFIER
Definition: error.h:89
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
@ ASN1_TYPE_OBJECT_IDENTIFIER
Definition: asn1.h:74
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:80
@ ERROR_WRONG_ENCODING
Definition: error.h:122
@ ERROR_INVALID_TAG
Definition: error.h:114
@ ASN1_TYPE_BMP_STRING
Definition: asn1.h:93
@ ERROR_INVALID_CLASS
Definition: error.h:117
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
error_t asn1ReadSequence(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an ASN.1 sequence from the input stream.
Definition: asn1.c:163
error_t asn1WriteInt32(int32_t value, bool_t reverse, uint8_t *data, size_t *written)
Write a 32-bit integer to the output stream.
Definition: asn1.c:645
@ ASN1_TYPE_NUMERIC_STRING
Definition: asn1.h:82
@ ASN1_TYPE_BOOLEAN
Definition: asn1.h:69
const uint8_t * value
Definition: asn1.h:107
error_t asn1CheckTag(const Asn1Tag *tag, bool_t constructed, uint_t objClass, uint_t objType)
Enforce the type of a specified tag.
Definition: asn1.c:803
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint_t objType
Definition: asn1.h:105
#define osMemmove(dest, src, length)
Definition: os_port.h:150
ASN.1 (Abstract Syntax Notation One)
@ ASN1_TYPE_GENERAL_STRING
Definition: asn1.h:91