Mirror of :pserver:cvs@cvs.fefe.de:/cvs libowfat https://www.fefe.de/libowfat/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

79 lines
3.1 KiB

  1. #include "scan.h"
  2. /* ASN.1 DER encoded length:
  3. * if (value<=0x80):
  4. * emit value;
  5. * otherwise:
  6. * emit 0x80+bytes_that_follow
  7. * emit all the bytes in the number, number saved big endian
  8. * examples:
  9. * 5 -> 0x05
  10. * 0xc2 -> 0x81 0xc2
  11. * 0x123 -> 0x82 0x01 0x23
  12. * 0x12345 -> 0x83 0x01 0x23 0x45
  13. */
  14. /* We provide two functions.
  15. * One that only parses the length value (scan_asn1derlengthvalue), and
  16. * one that also makes sure that as many bytes as specified by the
  17. * length are in the input buffer (scan_asn1derlength).
  18. * If you are trying to parse ASN.1, use scan_asn1derlength.
  19. * If you just want to use the integer encoding format used by ASN.1 DER
  20. * for lengths, use scan_asn1derlengthvalue. */
  21. size_t scan_asn1derlengthvalue(const char* src,size_t len,unsigned long long* value) {
  22. if (len==0 || len>=-(uintptr_t)src) return 0;
  23. unsigned int i,c=*src;
  24. unsigned long long l;
  25. if ((c&0x80)==0) {
  26. *value=c;
  27. return 1;
  28. }
  29. /* Highest bit set: lower 7 bits is the length of the length value in bytes. */
  30. c&=0x7f;
  31. if (!c) return 0; /* length 0x80 means indefinite length encoding, not supported here */
  32. l=(unsigned char)src[1];
  33. if (l==0) return 0; /* not minimally encoded: 0x82 0x00 0xc2 instead of 0x81 0xc2 */
  34. if (c>sizeof(l)) return 0; /* too many bytes, does not fit into target integer type */
  35. if (c+1>len) return 0; /* not enough data in input buffer */
  36. for (i=2; i<=c; ++i)
  37. l=l*256+(unsigned char)src[i];
  38. if (l<0x7f) return 0; /* not minimally encoded: 0x81 0x70 instead of 0x70 */
  39. *value=l;
  40. return i;
  41. }
  42. size_t scan_asn1derlength(const char* src,size_t len,unsigned long long* value) {
  43. unsigned long long l;
  44. size_t i=scan_asn1derlengthvalue(src,len,&l);
  45. if (!i || l > len-i) return 0; /* make sure data would fit into buffer */
  46. *value=l;
  47. return i;
  48. }
  49. #ifdef UNITTEST
  50. #include <assert.h>
  51. int main() {
  52. unsigned long long i;
  53. /* first check actual parsing */
  54. assert(scan_asn1derlengthvalue("\x05",1,&i)==1 && i==5);
  55. assert(scan_asn1derlengthvalue("\x81\xc2",2,&i)==2 && i==0xc2);
  56. assert(scan_asn1derlengthvalue("\x82\x01\x23",3,&i)==3 && i==0x123);
  57. assert(scan_asn1derlengthvalue("\x83\x01\x23\x45",4,&i)==4 && i==0x12345);
  58. assert(scan_asn1derlengthvalue("\x83\x01\x23\x45",5,&i)==4 && i==0x12345);
  59. assert(scan_asn1derlengthvalue("\x80",1,&i)==0); // reject indefinite length encoding
  60. assert(scan_asn1derlengthvalue("\x81\x05",2,&i)==0); // reject non-minimal encoding
  61. assert(scan_asn1derlengthvalue("\x81\xc2",1,&i)==0); // reject truncated message
  62. assert(scan_asn1derlengthvalue("\x82\xc2",2,&i)==0); // reject truncated message
  63. assert(scan_asn1derlengthvalue("\x82\x00\xc2",3,&i)==0); // reject non-minimal encoding
  64. assert(scan_asn1derlengthvalue("\x89\x01\x02\x03\x04\x05\x06\x07\x08\x09",10,&i)==0); // value does not fit in target integer
  65. /* now check buffer length checking in scan_asn1derlength */
  66. assert(scan_asn1derlength("\x01",2,&i)==1 && i==1); // ok
  67. assert(scan_asn1derlength("\x02",2,&i)==0); // buffer too small
  68. assert(scan_asn1derlength("\x88\xff\xff\xff\xff\xff\xff\xff\xff",9,&i)==0); // buffer too small, and integer overflow in naive check
  69. return 0;
  70. }
  71. #endif