summaryrefslogtreecommitdiffstats
path: root/scan_asn1length.c
blob: 150de949ece146878ca0b887ea1b2eeb918ccd7f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <inttypes.h>
#include "asn1.h"

size_t scan_asn1length(const char* src,const char* max,size_t* value) {
  size_t len=max-src;
  if (len==0 || len>=-(uintptr_t)src) return 0;
  unsigned int i,c=*src;
  size_t l;
  if ((c&0x80)==0) {
    l=c&0x7f;
    i=1;
  } else {
    /* Highest bit set: lower 7 bits is the length of the length value in bytes. */
    c&=0x7f;
    if (!c) return 0;		/* length 0x80 means indefinite length encoding, not supported here */
    l=(unsigned char)src[1];
    //if (l==0) return 0;		/* not minimally encoded: 0x81 0x00 instead of 0x00 XXX: We need to support this for Active Directory support :/ */
    if (c>sizeof(l)) return 0;	/* too many bytes, does not fit into target integer type */
    if (c+1>len) return 0;	/* not enough data in input buffer */
    for (i=2; i<=c; ++i)
      l=l*256+(unsigned char)src[i];
    //if (l<0x7f) return 0;	/* not minimally encoded: 0x81 0x70 instead of 0x70 XXX: Same AD issue as above */
  }
  if (l>len-i) return 0;	/* if the length would not fit into the buffer, return 0 */
  *value=l;
  return i;
}