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.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/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
498  * @return Error code
499  **/
500 
501 error_t asn1WriteHeader(Asn1Tag *tag, bool_t reverse, uint8_t *data,
502  size_t *written)
503 {
504  size_t i;
505  size_t m;
506  size_t n;
507 
508  //Compute the number of octets that are necessary to encode the tag number
509  if(tag->objType < 31)
510  {
511  m = 0;
512  }
513  else if(tag->objType < 128)
514  {
515  m = 1;
516  }
517  else if(tag->objType < 16384)
518  {
519  m = 2;
520  }
521  else if(tag->objType < 2097152)
522  {
523  m = 3;
524  }
525  else if(tag->objType < 268435456)
526  {
527  m = 4;
528  }
529  else
530  {
531  m = 5;
532  }
533 
534  //Compute the number of octets that are necessary to encode the length field
535  if(tag->length < 128)
536  {
537  n = 0;
538  }
539  else if(tag->length < 256)
540  {
541  n = 1;
542  }
543  else if(tag->length < 65536)
544  {
545  n = 2;
546  }
547  else if(tag->length < 16777216)
548  {
549  n = 3;
550  }
551  else
552  {
553  n = 4;
554  }
555 
556  //Valid output stream?
557  if(data != NULL)
558  {
559  //Use reverse encoding?
560  if(reverse)
561  {
562  //Move backward
563  data -= m + n + 2;
564  }
565 
566  //Save the class of the ASN.1 tag
567  data[0] = tag->objClass;
568 
569  //Primitive or constructed encoding?
570  if(tag->constructed)
571  {
573  }
574 
575  //Encode the tag number
576  if(m == 0)
577  {
578  //Tag number is in the range 0 to 30
579  data[0] |= tag->objType;
580  }
581  else
582  {
583  //The tag number is greater than or equal to 31
585 
586  //The subsequent octets will encode the tag number
587  for(i = 0; i < m; i++)
588  {
589  //Bits 7 to 1 encode the tag number
590  data[m - i] = (tag->objType >> (i * 7)) & 0x7F;
591 
592  //Bit 8 of each octet shall be set to one unless it is the
593  //last octet of the identifier octets
594  if(i != 0)
595  {
596  data[m - i] |= 0x80;
597  }
598  }
599  }
600 
601  //Encode the length field
602  if(n == 0)
603  {
604  //Use short form encoding
605  data[1 + m] = tag->length & 0x7F;
606  }
607  else
608  {
609  //Bits 7 to 1 encode the number of octets in the length field
610  data[1 + m] = 0x80 | (n & 0x7F);
611 
612  //The subsequent octets will encode the length field
613  for(i = 0; i < n; i++)
614  {
615  data[1 + m + n - i] = (tag->length >> (i * 8)) & 0xFF;
616  }
617  }
618  }
619 
620  //Total length occupied by the ASN.1 tag
621  tag->totalLength = tag->length + m + n + 2;
622 
623  //The last parameter is optional
624  if(written != NULL)
625  {
626  //Number of bytes written to the output stream
627  *written = m + n + 2;
628  }
629 
630  //Successful processing
631  return NO_ERROR;
632 }
633 
634 
635 /**
636  * @brief Insert an ASN.1 tag header
637  * @param[in] tag Structure describing the ASN.1 tag
638  * @param[out] data Output stream where to write the tag (optional parameter)
639  * @param[out] written Number of bytes written to the output stream
640  * @return Error code
641  **/
642 
643 error_t asn1InsertHeader(Asn1Tag *tag, uint8_t *data, size_t *written)
644 {
645  size_t i;
646  size_t m;
647  size_t n;
648 
649  //Compute the number of octets that are necessary to encode the tag number
650  if(tag->objType < 31)
651  {
652  m = 0;
653  }
654  else if(tag->objType < 128)
655  {
656  m = 1;
657  }
658  else if(tag->objType < 16384)
659  {
660  m = 2;
661  }
662  else if(tag->objType < 2097152)
663  {
664  m = 3;
665  }
666  else if(tag->objType < 268435456)
667  {
668  m = 4;
669  }
670  else
671  {
672  m = 5;
673  }
674 
675  //Compute the number of octets that are necessary to encode the length field
676  if(tag->length < 128)
677  {
678  n = 0;
679  }
680  else if(tag->length < 256)
681  {
682  n = 1;
683  }
684  else if(tag->length < 65536)
685  {
686  n = 2;
687  }
688  else if(tag->length < 16777216)
689  {
690  n = 3;
691  }
692  else
693  {
694  n = 4;
695  }
696 
697  //Valid output stream?
698  if(data != NULL)
699  {
700  //Make room for the ASN.1 tag header
701  osMemmove(data + m + n + 2, data, tag->length);
702 
703  //Save the class of the ASN.1 tag
704  data[0] = tag->objClass;
705 
706  //Primitive or constructed encoding?
707  if(tag->constructed)
708  {
710  }
711 
712  //Encode the tag number
713  if(m == 0)
714  {
715  //Tag number is in the range 0 to 30
716  data[0] |= tag->objType;
717  }
718  else
719  {
720  //The tag number is greater than or equal to 31
722 
723  //The subsequent octets will encode the tag number
724  for(i = 0; i < m; i++)
725  {
726  //Bits 7 to 1 encode the tag number
727  data[m - i] = (tag->objType >> (i * 7)) & 0x7F;
728 
729  //Bit 8 of each octet shall be set to one unless it is the
730  //last octet of the identifier octets
731  if(i != 0)
732  {
733  data[m - i] |= 0x80;
734  }
735  }
736  }
737 
738  //Encode the length field
739  if(n == 0)
740  {
741  //Use short form encoding
742  data[1 + m] = tag->length & 0x7F;
743  }
744  else
745  {
746  //Bits 7 to 1 encode the number of octets in the length field
747  data[1 + m] = 0x80 | (n & 0x7F);
748 
749  //The subsequent octets will encode the length field
750  for(i = 0; i < n; i++)
751  {
752  data[1 + m + n - i] = (tag->length >> (i * 8)) & 0xFF;
753  }
754  }
755  }
756 
757  //Total length occupied by the ASN.1 tag
758  tag->totalLength = tag->length + m + n + 2;
759 
760  //The last parameter is optional
761  if(written != NULL)
762  {
763  //Number of bytes written to the output stream
764  *written = m + n + 2;
765  }
766 
767  //Successful processing
768  return NO_ERROR;
769 }
770 
771 
772 /**
773  * @brief Write a 32-bit integer to the output stream
774  * @param[in] value Integer value
775  * @param[in] reverse Use reverse encoding
776  * @param[out] data Output stream where to write the tag (optional parameter)
777  * @param[out] written Number of bytes written to the output stream
778  * @return Error code
779  **/
780 
781 error_t asn1WriteInt32(int32_t value, bool_t reverse, uint8_t *data,
782  size_t *written)
783 {
784  size_t i;
785  size_t n;
786  uint16_t msb;
787 
788  //An integer value is always encoded in the smallest possible number of
789  //octets
790  for(n = 4; n > 1; n--)
791  {
792  //Retrieve the upper 9 bits
793  msb = (value >> (n * 8 - 9)) & 0x01FF;
794 
795  //The upper 9 bits shall not have the same value (all 0 or all 1)
796  if(msb != 0x0000 && msb != 0x01FF)
797  break;
798  }
799 
800  //Valid output stream?
801  if(data != NULL)
802  {
803  //Use reverse encoding?
804  if(reverse)
805  data -= n + 2;
806 
807  //Write tag type
809  //Write tag length
810  data[1] = n & 0xFF;
811 
812  //Write contents octets
813  for(i = 0; i < n; i++)
814  {
815  data[1 + n - i] = (value >> (i * 8)) & 0xFF;
816  }
817  }
818 
819  //The last parameter is optional
820  if(written != NULL)
821  {
822  //Number of bytes written to the output stream
823  *written = n + 2;
824  }
825 
826  //Successful processing
827  return NO_ERROR;
828 }
829 
830 
831 #if (MPI_SUPPORT == ENABLED)
832 
833 /**
834  * @brief Read a multiple-precision integer from the input stream
835  * @param[in] data Input stream where to read the tag
836  * @param[in] length Number of bytes available in the input stream
837  * @param[out] tag Structure describing the ASN.1 tag
838  * @param[out] value Integer value
839  * @return Error code
840  **/
841 
842 error_t asn1ReadMpi(const uint8_t *data, size_t length, Asn1Tag *tag,
843  Mpi *value)
844 {
845  error_t error;
846 
847  //Read ASN.1 tag
848  error = asn1ReadTag(data, length, tag);
849  //Failed to decode ASN.1 tag?
850  if(error)
851  return error;
852 
853  //Enforce encoding, class and type
855  //Invalid tag?
856  if(error)
857  return error;
858 
859  //Negative integer?
860  if(tag->length > 0 && (tag->value[0] & 0x80) != 0)
861  return ERROR_INVALID_SYNTAX;
862 
863  //Convert the octet string to a multiple precision integer
864  error = mpiImport(value, tag->value, tag->length, MPI_FORMAT_BIG_ENDIAN);
865 
866  //Return status code
867  return error;
868 }
869 
870 
871 /**
872  * @brief Write a multiple-precision integer from the output stream
873  * @param[in] value Integer value
874  * @param[in] reverse Use reverse encoding
875  * @param[out] data Output stream where to write the tag (optional parameter)
876  * @param[out] written Number of bytes written to the output stream
877  * @return Error code
878  **/
879 
880 error_t asn1WriteMpi(const Mpi *value, bool_t reverse, uint8_t *data,
881  size_t *written)
882 {
883  error_t error;
884  size_t n;
885  Asn1Tag tag;
886 
887  //Retrieve the length of the multiple precision integer
889 
890  //An integer value is always encoded in the smallest possible number of
891  //octets
892  n = (n / 8) + 1;
893 
894  //Valid output stream?
895  if(data != NULL)
896  {
897  //Use reverse encoding?
898  if(reverse)
899  data -= n;
900 
901  //The value of the multiple precision integer is encoded MSB first
903  //Any error to report?
904  if(error)
905  return error;
906  }
907 
908  //The integer is encapsulated within an ASN.1 structure
909  tag.constructed = FALSE;
912  tag.length = n;
913  tag.value = data;
914 
915  //Compute the length of the corresponding ASN.1 structure
916  error = asn1WriteTag(&tag, FALSE, data, NULL);
917  //Any error to report?
918  if(error)
919  return error;
920 
921  //Number of bytes written to the output stream
922  if(written != NULL)
923  {
924  *written = tag.totalLength;
925  }
926 
927  //Successful processing
928  return NO_ERROR;
929 }
930 
931 #endif
932 
933 
934 /**
935  * @brief Enforce the type of a specified tag
936  * @param[in] tag Pointer to an ASN.1 tag
937  * @param[in] constructed Expected encoding (TRUE for constructed, FALSE
938  * for primitive)
939  * @param[in] objClass Expected tag class
940  * @param[in] objType Expected tag type
941  * @return Error code
942  **/
943 
944 error_t asn1CheckTag(const Asn1Tag *tag, bool_t constructed, uint_t objClass,
945  uint_t objType)
946 {
947  //Check encoding
948  if(tag->constructed != constructed)
949  return ERROR_WRONG_ENCODING;
950 
951  //Enforce class
952  if(tag->objClass != objClass)
953  return ERROR_INVALID_CLASS;
954 
955  //Enforce type
956  if(tag->objType != objType)
957  return ERROR_INVALID_TYPE;
958 
959  //The tag matches all the criteria
960  return NO_ERROR;
961 }
962 
963 
964 /**
965  * @brief Check ASN.1 tag against a specified OID
966  * @param[in] tag Pointer to an ASN.1 tag
967  * @param[in] oid Expected object identifier (OID)
968  * @param[in] length Length of the OID
969  * @return Error code
970  **/
971 
972 error_t asn1CheckOid(const Asn1Tag *tag, const uint8_t *oid, size_t length)
973 {
974  error_t error;
975 
976  //Enforce encoding, class and type
978  //Any error to report?
979  if(error)
980  return error;
981 
982  //Compare OID against the specified value
983  if(oidComp(tag->value, tag->length, oid, length))
984  return ERROR_WRONG_IDENTIFIER;
985 
986  //The tag matches all the criteria
987  return NO_ERROR;
988 }
989 
990 
991 /**
992  * @brief Display an ASN.1 data object
993  * @param[in] data Pointer to the ASN.1 object to dump
994  * @param[in] length Length of the ASN.1 object
995  * @param[in] level Current level of recursion (this parameter shall be set to 0)
996  * @return Error code
997  **/
998 
999 error_t asn1DumpObject(const uint8_t *data, size_t length, uint_t level)
1000 {
1001 //Check debugging level
1002 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
1003  error_t error;
1004  uint_t i;
1005  Asn1Tag tag;
1006 
1007  //ASN.1 universal types
1008  static const char_t *const label[32] =
1009  {
1010  "[0]",
1011  "BOOLEAN",
1012  "INTEGER",
1013  "BIT STRING",
1014  "OCTET STRING",
1015  "NULL",
1016  "OBJECT IDENTIFIER",
1017  "OBJECT DESCRIPTOR",
1018  "EXTERNAL",
1019  "REAL",
1020  "ENUMERATED",
1021  "[11]",
1022  "UTF8 STRING",
1023  "[13]",
1024  "[14]",
1025  "[15]",
1026  "SEQUENCE",
1027  "SET",
1028  "NUMERIC STRING",
1029  "PRINTABLE STRING",
1030  "TELETEX STRING",
1031  "VIDEOTEX STRING",
1032  "IA5 STRING",
1033  "UTC TIME",
1034  "GENERALIZED TIME",
1035  "GRAPHIC STRING",
1036  "VISIBLE STRING",
1037  "GENERAL STRING",
1038  "UNIVERSAL STRING",
1039  "[29]",
1040  "BMP STRING",
1041  "[31]"
1042  };
1043 
1044  //Prefix used to format the structure
1045  static const char_t *const prefix[12] =
1046  {
1047  "",
1048  " ",
1049  " ",
1050  " ",
1051  " ",
1052  " ",
1053  " ",
1054  " ",
1055  " ",
1056  " ",
1057  " ",
1058  " "
1059  };
1060 
1061  //Parse ASN.1 object
1062  while(length > 0)
1063  {
1064  //Decode current ASN.1 tag
1065  error = asn1ReadTag(data, length, &tag);
1066  //Decoding failed?
1067  if(error)
1068  return error;
1069 
1070  //Point to the next field
1071  data += tag.totalLength;
1072  length -= tag.totalLength;
1073 
1074  //Dump tag number, tag class, and contents length fields
1075  if(tag.objType < 32 && (tag.objClass & ASN1_CLASS_MASK) == ASN1_CLASS_UNIVERSAL)
1076  {
1077  TRACE_DEBUG("%s%s (%" PRIuSIZE " bytes)\r\n", prefix[level], label[tag.objType], tag.length);
1078  }
1079  else
1080  {
1081  TRACE_DEBUG("%s[%u] (%" PRIuSIZE " bytes)\r\n", prefix[level], tag.objType, tag.length);
1082  }
1083 
1084  //Constructed type?
1085  if(tag.constructed)
1086  {
1087  //Check whether the maximum level of recursion is reached
1088  if(level < 10)
1089  {
1090  //Recursive decoding of the ASN.1 tag
1091  error = asn1DumpObject(tag.value, tag.length, level + 1);
1092  //Decoding failed?
1093  if(error)
1094  return error;
1095  }
1096  else
1097  {
1098  //If the maximum level of recursion is reached, then dump contents
1099  TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length);
1100  }
1101  }
1102  else
1103  {
1104  //Universal tag?
1106  {
1107  //Check the type of the current tag
1108  switch(tag.objType)
1109  {
1110  //OID?
1112  //Append prefix
1113  TRACE_DEBUG("%s", prefix[level + 1]);
1114  //Print OID
1115  TRACE_DEBUG("%s", oidToString(tag.value, tag.length, NULL, 0));
1116  //Add a line feed
1117  TRACE_DEBUG("\r\n");
1118  break;
1119 
1120  //String?
1121  case ASN1_TYPE_UTF8_STRING:
1126  case ASN1_TYPE_IA5_STRING:
1131  case ASN1_TYPE_BMP_STRING:
1132  //Append prefix
1133  TRACE_DEBUG("%s", prefix[level + 1]);
1134 
1135  //Dump the entire string
1136  for(i = 0; i < tag.length; i++)
1137  {
1138  TRACE_DEBUG("%c", tag.value[i]);
1139  }
1140 
1141  //Add a line feed
1142  TRACE_DEBUG("\r\n");
1143  break;
1144 
1145  //UTC time?
1146  case ASN1_TYPE_UTC_TIME:
1147  //Check length
1148  if(tag.length != 13)
1149  return ERROR_WRONG_ENCODING;
1150  //The encoding shall terminate with a "Z"
1151  if(tag.value[tag.length - 1] != 'Z')
1152  return ERROR_WRONG_ENCODING;
1153 
1154  //Append prefix
1155  TRACE_DEBUG("%s", prefix[level + 1]);
1156  //Display date
1157  TRACE_DEBUG("%c%c/%c%c/%c%c ", tag.value[0], tag.value[1],
1158  tag.value[2], tag.value[3], tag.value[4], tag.value[5]);
1159  //Display time
1160  TRACE_DEBUG("%c%c:%c%c:%c%c", tag.value[6], tag.value[7],
1161  tag.value[8], tag.value[9], tag.value[10], tag.value[11]);
1162  //Add a line feed
1163  TRACE_DEBUG("\r\n");
1164  break;
1165 
1166  //Generalized time?
1168  //Check length
1169  if(tag.length != 15)
1170  return ERROR_WRONG_ENCODING;
1171  //The encoding shall terminate with a "Z"
1172  if(tag.value[tag.length - 1] != 'Z')
1173  return ERROR_WRONG_ENCODING;
1174 
1175  //Append prefix
1176  TRACE_DEBUG("%s", prefix[level + 1]);
1177  //Display date
1178  TRACE_DEBUG("%c%c%c%c/%c%c/%c%c ", tag.value[0], tag.value[1], tag.value[2],
1179  tag.value[3], tag.value[4], tag.value[5], tag.value[6], tag.value[7]);
1180  //Display time
1181  TRACE_DEBUG("%c%c:%c%c:%c%c", tag.value[8], tag.value[9],
1182  tag.value[10], tag.value[11], tag.value[12], tag.value[13]);
1183  //Add a line feed
1184  TRACE_DEBUG("\r\n");
1185  break;
1186 
1187  //Any other type?
1188  default:
1189  //Dump the contents of the tag
1190  TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length);
1191  break;
1192  }
1193  }
1194  else
1195  {
1196  //Dump the contents of the tag
1197  TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length);
1198  }
1199  }
1200  }
1201 #endif
1202 
1203  //ASN.1 object successfully decoded
1204  return NO_ERROR;
1205 }
1206 
1207 #endif
@ ASN1_TYPE_UTC_TIME
Definition: asn1.h:90
@ ASN1_TYPE_GENERALIZED_TIME
Definition: asn1.h:91
int bool_t
Definition: compiler_port.h:61
Arbitrary precision integer.
Definition: mpi.h:102
@ ASN1_TYPE_VIDEOTEX_STRING
Definition: asn1.h:88
#define ASN1_CLASS_MASK
Definition: asn1.h:51
OID (Object Identifier)
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:224
error_t asn1WriteHeader(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written)
Write an ASN.1 tag header.
Definition: asn1.c:501
error_t asn1InsertHeader(Asn1Tag *tag, uint8_t *data, size_t *written)
Insert an ASN.1 tag header.
Definition: asn1.c:643
@ ASN1_TYPE_UTF8_STRING
Definition: asn1.h:82
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:999
@ ASN1_TYPE_IA5_STRING
Definition: asn1.h:89
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:111
size_t length
Definition: asn1.h:109
#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:92
ASN.1 tag.
Definition: asn1.h:105
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:95
#define ASN1_TAG_NUMBER_MASK
Definition: asn1.h:43
@ ASN1_TYPE_VISIBLE_STRING
Definition: asn1.h:93
@ 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:880
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:107
@ ASN1_TYPE_PRINTABLE_STRING
Definition: asn1.h:86
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:972
@ ASN1_TYPE_TELETEX_STRING
Definition: asn1.h:87
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:254
@ ASN1_TYPE_OCTET_STRING
Definition: asn1.h:75
@ ASN1_TYPE_INTEGER
Definition: asn1.h:73
#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:842
uint8_t value[]
Definition: tcp.h:376
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:93
bool_t constructed
Definition: asn1.h:106
@ ERROR_WRONG_IDENTIFIER
Definition: error.h:89
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
@ ASN1_TYPE_OBJECT_IDENTIFIER
Definition: asn1.h:77
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:83
@ ERROR_WRONG_ENCODING
Definition: error.h:122
@ ERROR_INVALID_TAG
Definition: error.h:114
@ ASN1_TYPE_BMP_STRING
Definition: asn1.h:96
@ 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:781
@ ASN1_TYPE_NUMERIC_STRING
Definition: asn1.h:85
@ ASN1_TYPE_BOOLEAN
Definition: asn1.h:72
const uint8_t * value
Definition: asn1.h:110
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:944
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint_t objType
Definition: asn1.h:108
#define osMemmove(dest, src, length)
Definition: os_port.h:150
ASN.1 (Abstract Syntax Notation One)
@ ASN1_TYPE_GENERAL_STRING
Definition: asn1.h:94