static size_t decode_len(const uint8_t **ptr, const uint8_t *end) { const uint8_t *tmp = *ptr; size_t ret; if ( ber_len_form_short(*tmp) ) { ret = ber_len_short(*tmp); tmp++; }else{ size_t i, l; l = ber_len_short(*tmp); if ( l > 4 || tmp + l > end ) { *ptr = end; return 1; } tmp++; for(ret = i = 0; i < l; i++, tmp++) { ret <<= 8; ret |= *tmp; } } *ptr = tmp; return ret; }
static const uint8_t *do_decode_tag(struct gber_tag *tag, const uint8_t *ptr, size_t len) { const uint8_t *end = ptr + len; if ( len < 2 ) { printf("block too small\n"); return NULL; } tag->ber_id = *(ptr++); tag->ber_tag = tag->ber_id; if ( (tag->ber_id & 0x1f) == 0x1f ) { if ( (*ptr & 0x80) ) { printf("bad id\n"); return NULL; } tag->ber_tag <<= 8; tag->ber_tag |= *(ptr++); if ( ptr >= end ) { printf("tag too big\n"); return NULL; } } if ( ber_len_form_short(*ptr) ) { tag->ber_len = ber_len_short(*ptr); ptr++; }else{ unsigned int i; uint8_t ll; ll = ber_len_short(*(ptr++)); if ( ptr + ll > end || ll > 4 ) { printf("tag past end\n"); return NULL; } for(tag->ber_len = 0, i = 0; i < ll; i++, ptr++) { tag->ber_len <<= 8; tag->ber_len |= *ptr; } } return ptr; }
static const uint8_t *do_decode_tag(struct gber_tag *tag, const uint8_t *ptr, size_t len) { const uint8_t *end = ptr + len; if ( len < 2 ) return NULL; tag->ber_id = *(ptr++); tag->ber_tag = tag->ber_id; if ( (tag->ber_id & 0x1f) == 0x1f ) { if ( (*ptr & 0x80) ) return NULL; tag->ber_tag <<= 8; tag->ber_tag |= *(ptr++); if ( ptr >= end ) return NULL; } if ( ber_len_form_short(*ptr) ) { tag->ber_len = ber_len_short(*ptr); ptr++; }else{ unsigned int i; uint8_t ll; ll = ber_len_short(*(ptr++)); if ( ptr + ll > end || ll > 4 ) return NULL; for(tag->ber_len = 0, i = 0; i < ll; i++, ptr++) { tag->ber_len <<= 8; tag->ber_len |= *ptr; } } return ptr; }
void ber_dump(const uint8_t *buf, size_t len, unsigned int depth) { const uint8_t *end = buf + len; uint32_t clen, num, i; uint8_t idb; #if 0 const char * const clsname[]={ "universal", "application", "context-specific", "private", }; #endif again: if ( buf >= end ) return; idb = *buf; num = ber_id_octet_tag(*buf); buf++; /* FIXME: if ( tag == 0x1f ) get rest of type... */ if ( num >= 0x1f ) { for(num = 0, i = 0; buf < end; i++) { num <<= 7; num |= *buf & 0x7f; buf++; if ( !(*buf & 0x80) ) break; } } printf("%*c.tag = %u (0x%x)\n", depth, ' ', num, num); if ( buf >= end ) return; if ( ber_len_form_short(*buf) ) { clen = ber_len_short(*buf); buf++; }else{ uint32_t l; l = ber_len_short(*buf); if ( l > 4 || buf + l > end ) return; buf++; for(clen = i = 0; i < l; i++, buf++) { clen <<= 8; clen |= *buf; } } if ( buf + clen > end ) return; printf("%*c.len = %zu (0x%zx)", depth, ' ', len, len); if ( ber_id_octet_constructed(idb) ) { printf(" {\n"); ber_dump(buf, clen, depth + 2); printf("%*c}\n", depth, ' '); }else{ printf("\n"); hex_dump(buf, clen, 16, depth); } buf += clen; goto again; }