static int do_ber_dump(FILE *f, const uint8_t *ptr, size_t len, unsigned int depth) { const uint8_t *end = ptr + len; while (ptr < end) { struct gber_tag tag; ptr = ber_decode_tag(&tag, ptr, end - ptr); if (NULL == ptr) return 0; fprintf(f, "%*c.tag = %x\n", depth, ' ', tag.ber_tag); fprintf(f, "%*c.class = %s\n", depth, ' ', ber_id_octet_clsname(tag.ber_id)); fprintf(f, "%*c.constructed = %s\n", depth, ' ', ber_id_octet_constructed(tag.ber_id) ? "yes" : "no"); fprintf(f, "%*c.len = %zu (0x%.2zx)\n", depth, ' ', tag.ber_len, tag.ber_len); if (ber_id_octet_constructed(tag.ber_id)) { if (!do_ber_dump(f, ptr, tag.ber_len, depth + 1)) return 0; } else { hex_dumpf_r(f, ptr, tag.ber_len, 16, depth + 1); } ptr += tag.ber_len; } return 1; }
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; }