der.c revision 302221
1298178Sdelphij/*- 2298178Sdelphij * Copyright (c) 2016 Christos Zoulas 3298178Sdelphij * All rights reserved. 4298178Sdelphij * 5298178Sdelphij * Redistribution and use in source and binary forms, with or without 6298178Sdelphij * modification, are permitted provided that the following conditions 7298178Sdelphij * are met: 8298178Sdelphij * 1. Redistributions of source code must retain the above copyright 9298178Sdelphij * notice, this list of conditions and the following disclaimer. 10298178Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 11298178Sdelphij * notice, this list of conditions and the following disclaimer in the 12298178Sdelphij * documentation and/or other materials provided with the distribution. 13298178Sdelphij * 14298178Sdelphij * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 15298178Sdelphij * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16298178Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17298178Sdelphij * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18298178Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19298178Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20298178Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21298178Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22298178Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23298178Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24298178Sdelphij * POSSIBILITY OF SUCH DAMAGE. 25298178Sdelphij */ 26298178Sdelphij/* 27298178Sdelphij * DER (Distinguished Encoding Rules) Parser 28298178Sdelphij * 29298178Sdelphij * Sources: 30298178Sdelphij * https://en.wikipedia.org/wiki/X.690 31298178Sdelphij * http://fm4dd.com/openssl/certexamples.htm 32298178Sdelphij * http://blog.engelke.com/2014/10/17/parsing-ber-and-der-encoded-asn-1-objects/ 33298178Sdelphij */ 34298178Sdelphij#ifndef TEST_DER 35298178Sdelphij#include "file.h" 36298178Sdelphij 37298178Sdelphij#ifndef lint 38302221SdelphijFILE_RCSID("@(#)$File: der.c,v 1.7 2016/06/01 22:01:15 christos Exp $") 39298178Sdelphij#endif 40298178Sdelphij#endif 41298178Sdelphij 42298178Sdelphij#include <sys/types.h> 43298178Sdelphij#include <sys/stat.h> 44298178Sdelphij#include <sys/mman.h> 45298178Sdelphij 46298178Sdelphij#include <stdio.h> 47298178Sdelphij#include <fcntl.h> 48298178Sdelphij#include <stdlib.h> 49298178Sdelphij#include <string.h> 50298178Sdelphij#include <ctype.h> 51298178Sdelphij 52298178Sdelphij#ifndef TEST_DER 53298178Sdelphij#include "magic.h" 54298178Sdelphij#include "der.h" 55299736Sdelphij#else 56299736Sdelphij#include <err.h> 57298178Sdelphij#endif 58298178Sdelphij 59298178Sdelphij#define DER_BAD ((uint32_t)-1) 60298178Sdelphij 61298178Sdelphij#define DER_CLASS_UNIVERSAL 0 62298178Sdelphij#define DER_CLASS_APPLICATION 1 63298178Sdelphij#define DER_CLASS_CONTEXT 2 64298178Sdelphij#define DER_CLASS_PRIVATE 3 65299736Sdelphij#ifdef DEBUG_DER 66298178Sdelphijstatic const char der_class[] = "UACP"; 67299736Sdelphij#endif 68298178Sdelphij 69298178Sdelphij#define DER_TYPE_PRIMITIVE 0 70298178Sdelphij#define DER_TYPE_CONSTRUCTED 1 71299736Sdelphij#ifdef DEBUG_DER 72298178Sdelphijstatic const char der_type[] = "PC"; 73299736Sdelphij#endif 74298178Sdelphij 75298178Sdelphij#define DER_TAG_EOC 0x00 76298178Sdelphij#define DER_TAG_BOOLEAN 0x01 77298178Sdelphij#define DER_TAG_INTEGER 0x02 78298178Sdelphij#define DER_TAG_BIT STRING 0x03 79298178Sdelphij#define DER_TAG_OCTET_STRING 0x04 80298178Sdelphij#define DER_TAG_NULL 0x05 81298178Sdelphij#define DER_TAG_OBJECT_IDENTIFIER 0x06 82298178Sdelphij#define DER_TAG_OBJECT_DESCRIPTOR 0x07 83298178Sdelphij#define DER_TAG_EXTERNAL 0x08 84298178Sdelphij#define DER_TAG_REAL 0x09 85298178Sdelphij#define DER_TAG_ENUMERATED 0x0a 86298178Sdelphij#define DER_TAG_EMBEDDED_PDV 0x0b 87298178Sdelphij#define DER_TAG_UTF8_STRING 0x0c 88298178Sdelphij#define DER_TAG_RELATIVE_OID 0x0d 89298178Sdelphij#define DER_TAG_RESERVED_1 0x0e 90298178Sdelphij#define DER_TAG_RESERVED_2 0x0f 91298178Sdelphij#define DER_TAG_SEQUENCE 0x10 92298178Sdelphij#define DER_TAG_SET 0x11 93298178Sdelphij#define DER_TAG_NUMERIC_STRING 0x12 94298178Sdelphij#define DER_TAG_PRINTABLE_STRING 0x13 95298178Sdelphij#define DER_TAG_T61_STRING 0x14 96298178Sdelphij#define DER_TAG_VIDEOTEX_STRING 0x15 97298178Sdelphij#define DER_TAG_IA5_STRING 0x16 98298178Sdelphij#define DER_TAG_UTCTIME 0x17 99298178Sdelphij#define DER_TAG_GENERALIZED_TIME 0x18 100298178Sdelphij#define DER_TAG_GRAPHIC_STRING 0x19 101298178Sdelphij#define DER_TAG_VISIBLE_STRING 0x1a 102298178Sdelphij#define DER_TAG_GENERAL_STRING 0x1b 103298178Sdelphij#define DER_TAG_UNIVERSAL_STRING 0x1c 104298178Sdelphij#define DER_TAG_CHARACTER_STRING 0x1d 105298178Sdelphij#define DER_TAG_BMP_STRING 0x1e 106298178Sdelphij#define DER_TAG_LONG 0x1f 107298178Sdelphij 108298178Sdelphijstatic const char *der__tag[] = { 109298178Sdelphij "eoc", "bool", "int", "bit_str", "octet_str", 110298178Sdelphij "null", "obj_id", "obj_desc", "ext", "real", 111298178Sdelphij "enum", "embed", "utf8_str", "oid", "res1", 112298178Sdelphij "res2", "seq", "set", "num_str", "prt_str", 113298178Sdelphij "t61_str", "vid_str", "ia5_str", "utc_time", 114298178Sdelphij "gen_time", "gr_str", "vis_str", "gen_str", 115298178Sdelphij "char_str", "bmp_str", "long" 116298178Sdelphij}; 117298178Sdelphij 118298178Sdelphij#ifdef DEBUG_DER 119298178Sdelphij#define DPRINTF(a) printf a 120298178Sdelphij#else 121298178Sdelphij#define DPRINTF(a) 122298178Sdelphij#endif 123298178Sdelphij 124298178Sdelphij#ifdef TEST_DER 125298178Sdelphijstatic uint8_t 126298178Sdelphijgetclass(uint8_t c) 127298178Sdelphij{ 128298178Sdelphij return c >> 6; 129298178Sdelphij} 130298178Sdelphij 131298178Sdelphijstatic uint8_t 132298178Sdelphijgettype(uint8_t c) 133298178Sdelphij{ 134298178Sdelphij return (c >> 5) & 1; 135298178Sdelphij} 136298178Sdelphij#endif 137298178Sdelphij 138298178Sdelphijstatic uint32_t 139298178Sdelphijgettag(const uint8_t *c, size_t *p, size_t l) 140298178Sdelphij{ 141298178Sdelphij uint32_t tag; 142298178Sdelphij 143298178Sdelphij if (*p >= l) 144298178Sdelphij return DER_BAD; 145298178Sdelphij 146298178Sdelphij tag = c[(*p)++] & 0x1f; 147298178Sdelphij 148298178Sdelphij if (tag != 0x1f) 149298178Sdelphij return tag; 150298178Sdelphij 151298178Sdelphij if (*p >= l) 152298178Sdelphij return DER_BAD; 153298178Sdelphij 154298178Sdelphij while (c[*p] >= 0x80) { 155298178Sdelphij tag = tag * 128 + c[(*p)++] - 0x80; 156298178Sdelphij if (*p >= l) 157298178Sdelphij return DER_BAD; 158298178Sdelphij } 159298178Sdelphij return tag; 160298178Sdelphij} 161298178Sdelphij 162298178Sdelphijstatic uint32_t 163298178Sdelphijgetlength(const uint8_t *c, size_t *p, size_t l) 164298178Sdelphij{ 165298178Sdelphij uint8_t digits, i; 166298178Sdelphij size_t len; 167298178Sdelphij 168298178Sdelphij if (*p >= l) 169298178Sdelphij return DER_BAD; 170298178Sdelphij 171298178Sdelphij digits = c[(*p)++]; 172298178Sdelphij 173298178Sdelphij if ((digits & 0x80) == 0) 174298178Sdelphij return digits; 175298178Sdelphij 176298178Sdelphij digits &= 0x7f; 177298178Sdelphij len = 0; 178298178Sdelphij 179298178Sdelphij if (*p + digits >= l) 180298178Sdelphij return DER_BAD; 181298178Sdelphij 182298178Sdelphij for (i = 0; i < digits; i++) 183298178Sdelphij len = (len << 8) | c[(*p)++]; 184298178Sdelphij return len; 185298178Sdelphij} 186298178Sdelphij 187298178Sdelphijstatic const char * 188298178Sdelphijder_tag(char *buf, size_t len, uint32_t tag) 189298178Sdelphij{ 190298178Sdelphij if (tag < DER_TAG_LONG) 191298178Sdelphij strlcpy(buf, der__tag[tag], len); 192298178Sdelphij else 193298178Sdelphij snprintf(buf, len, "%#x", tag); 194298178Sdelphij return buf; 195298178Sdelphij} 196298178Sdelphij 197298178Sdelphij#ifndef TEST_DER 198298178Sdelphijstatic int 199298178Sdelphijder_data(char *buf, size_t blen, uint32_t tag, const void *q, uint32_t len) 200298178Sdelphij{ 201298178Sdelphij const uint8_t *d = q; 202298178Sdelphij switch (tag) { 203298178Sdelphij case DER_TAG_PRINTABLE_STRING: 204298178Sdelphij case DER_TAG_UTF8_STRING: 205298178Sdelphij case DER_TAG_IA5_STRING: 206298178Sdelphij case DER_TAG_UTCTIME: 207298178Sdelphij return snprintf(buf, blen, "%.*s", len, (const char *)q); 208298178Sdelphij default: 209298178Sdelphij break; 210298178Sdelphij } 211298178Sdelphij 212298178Sdelphij for (uint32_t i = 0; i < len; i++) { 213298178Sdelphij uint32_t z = i << 1; 214298178Sdelphij if (z < blen - 2) 215298178Sdelphij snprintf(buf + z, blen - z, "%.2x", d[i]); 216298178Sdelphij } 217298178Sdelphij return len * 2; 218298178Sdelphij} 219298178Sdelphij 220298178Sdelphijint32_t 221298178Sdelphijder_offs(struct magic_set *ms, struct magic *m, size_t nbytes) 222298178Sdelphij{ 223298178Sdelphij const uint8_t *b = CAST(const void *, ms->search.s); 224302221Sdelphij size_t offs = 0, len = ms->search.s_len ? ms->search.s_len : nbytes; 225298178Sdelphij 226298178Sdelphij if (gettag(b, &offs, len) == DER_BAD) 227298178Sdelphij return -1; 228298178Sdelphij DPRINTF(("%s1: %d %zu %u\n", __func__, ms->offset, offs, m->offset)); 229298178Sdelphij 230298178Sdelphij uint32_t tlen = getlength(b, &offs, len); 231298178Sdelphij if (tlen == DER_BAD) 232298178Sdelphij return -1; 233298178Sdelphij DPRINTF(("%s2: %d %zu %u\n", __func__, ms->offset, offs, tlen)); 234298178Sdelphij 235298178Sdelphij offs += ms->offset + m->offset; 236298178Sdelphij DPRINTF(("cont_level = %d\n", m->cont_level)); 237298178Sdelphij#ifdef DEBUG_DER 238298178Sdelphij for (size_t i = 0; i < m->cont_level; i++) 239298178Sdelphij printf("cont_level[%zu] = %u\n", i, ms->c.li[i].off); 240298178Sdelphij#endif 241298178Sdelphij if (m->cont_level != 0) { 242298178Sdelphij if (offs + tlen > nbytes) 243298178Sdelphij return DER_BAD; 244298178Sdelphij ms->c.li[m->cont_level - 1].off = offs + tlen; 245298178Sdelphij DPRINTF(("cont_level[%u] = %u\n", m->cont_level - 1, 246298178Sdelphij ms->c.li[m->cont_level - 1].off)); 247298178Sdelphij } 248298178Sdelphij return offs; 249298178Sdelphij} 250298178Sdelphij 251298178Sdelphijint 252298178Sdelphijder_cmp(struct magic_set *ms, struct magic *m) 253298178Sdelphij{ 254298178Sdelphij const uint8_t *b = CAST(const void *, ms->search.s); 255298178Sdelphij const char *s = m->value.s; 256298178Sdelphij size_t offs = 0, len = ms->search.s_len; 257298178Sdelphij uint32_t tag, tlen; 258298178Sdelphij char buf[128]; 259298178Sdelphij 260298178Sdelphij tag = gettag(b, &offs, len); 261298178Sdelphij if (tag == DER_BAD) 262298178Sdelphij return -1; 263298178Sdelphij 264298178Sdelphij tlen = getlength(b, &offs, len); 265298178Sdelphij if (tlen == DER_BAD) 266298178Sdelphij return -1; 267298178Sdelphij 268298178Sdelphij der_tag(buf, sizeof(buf), tag); 269298178Sdelphij if ((ms->flags & MAGIC_DEBUG) != 0) 270298178Sdelphij fprintf(stderr, "%s: tag %p got=%s exp=%s\n", __func__, b, 271298178Sdelphij buf, s); 272298178Sdelphij size_t slen = strlen(buf); 273298178Sdelphij 274298178Sdelphij if (strncmp(buf, s, slen) != 0) 275298178Sdelphij return 0; 276298178Sdelphij 277298178Sdelphij s += slen; 278298178Sdelphij 279298178Sdelphijagain: 280298178Sdelphij switch (*s) { 281298178Sdelphij case '\0': 282298178Sdelphij return 1; 283298178Sdelphij case '=': 284298178Sdelphij s++; 285298178Sdelphij goto val; 286298178Sdelphij default: 287298178Sdelphij if (!isdigit((unsigned char)*s)) 288298178Sdelphij return 0; 289298178Sdelphij 290298178Sdelphij slen = 0; 291298178Sdelphij do 292298178Sdelphij slen = slen * 10 + *s - '0'; 293298178Sdelphij while (isdigit((unsigned char)*++s)); 294298178Sdelphij if ((ms->flags & MAGIC_DEBUG) != 0) 295298178Sdelphij fprintf(stderr, "%s: len %zu %u\n", __func__, 296298178Sdelphij slen, tlen); 297298178Sdelphij if (tlen != slen) 298298178Sdelphij return 0; 299298178Sdelphij goto again; 300298178Sdelphij } 301298178Sdelphijval: 302298178Sdelphij DPRINTF(("%s: before data %zu %u\n", __func__, offs, tlen)); 303298178Sdelphij der_data(buf, sizeof(buf), tag, b + offs, tlen); 304298178Sdelphij if ((ms->flags & MAGIC_DEBUG) != 0) 305298178Sdelphij fprintf(stderr, "%s: data %s %s\n", __func__, buf, s); 306298178Sdelphij if (strcmp(buf, s) != 0 && strcmp("x", s) != 0) 307298178Sdelphij return 0; 308298178Sdelphij strlcpy(ms->ms_value.s, buf, sizeof(ms->ms_value.s)); 309298178Sdelphij return 1; 310298178Sdelphij} 311298178Sdelphij#endif 312298178Sdelphij 313298178Sdelphij#ifdef TEST_DER 314298178Sdelphijstatic void 315298178Sdelphijprinttag(uint32_t tag, const void *q, uint32_t len) 316298178Sdelphij{ 317298178Sdelphij const uint8_t *d = q; 318298178Sdelphij switch (tag) { 319298178Sdelphij case DER_TAG_PRINTABLE_STRING: 320298178Sdelphij case DER_TAG_UTF8_STRING: 321298178Sdelphij printf("%.*s\n", len, (const char *)q); 322298178Sdelphij return; 323298178Sdelphij default: 324298178Sdelphij break; 325298178Sdelphij } 326298178Sdelphij 327298178Sdelphij for (uint32_t i = 0; i < len; i++) 328298178Sdelphij printf("%.2x", d[i]); 329298178Sdelphij printf("\n"); 330298178Sdelphij} 331298178Sdelphij 332298178Sdelphijstatic void 333298178Sdelphijprintdata(size_t level, const void *v, size_t x, size_t l) 334298178Sdelphij{ 335298178Sdelphij const uint8_t *p = v, *ep = p + l; 336298178Sdelphij size_t ox; 337298178Sdelphij char buf[128]; 338298178Sdelphij 339298178Sdelphij while (p + x < ep) { 340298178Sdelphij const uint8_t *q; 341298178Sdelphij uint8_t c = getclass(p[x]); 342298178Sdelphij uint8_t t = gettype(p[x]); 343298178Sdelphij ox = x; 344298178Sdelphij if (x != 0) 345298178Sdelphij printf("%.2x %.2x %.2x\n", p[x - 1], p[x], p[x + 1]); 346298178Sdelphij uint32_t tag = gettag(p, &x, ep - p + x); 347298178Sdelphij if (p + x >= ep) 348298178Sdelphij break; 349298178Sdelphij uint32_t len = getlength(p, &x, ep - p + x); 350298178Sdelphij 351298178Sdelphij printf("%zu %zu-%zu %c,%c,%s,%u:", level, ox, x, 352298178Sdelphij der_class[c], der_type[t], 353298178Sdelphij der_tag(buf, sizeof(buf), tag), len); 354298178Sdelphij q = p + x; 355298178Sdelphij if (p + len > ep) 356298178Sdelphij errx(EXIT_FAILURE, "corrupt der"); 357298178Sdelphij printtag(tag, q, len); 358298178Sdelphij if (t != DER_TYPE_PRIMITIVE) 359298178Sdelphij printdata(level + 1, p, x, len + x); 360298178Sdelphij x += len; 361298178Sdelphij } 362298178Sdelphij} 363298178Sdelphij 364298178Sdelphijint 365298178Sdelphijmain(int argc, char *argv[]) 366298178Sdelphij{ 367298178Sdelphij int fd; 368298178Sdelphij struct stat st; 369298178Sdelphij size_t l; 370298178Sdelphij void *p; 371298178Sdelphij 372298178Sdelphij if ((fd = open(argv[1], O_RDONLY)) == -1) 373298178Sdelphij err(EXIT_FAILURE, "open `%s'", argv[1]); 374298178Sdelphij if (fstat(fd, &st) == -1) 375298178Sdelphij err(EXIT_FAILURE, "stat `%s'", argv[1]); 376298178Sdelphij l = (size_t)st.st_size; 377298178Sdelphij if ((p = mmap(NULL, l, PROT_READ, MAP_FILE, fd, 0)) == MAP_FAILED) 378298178Sdelphij err(EXIT_FAILURE, "mmap `%s'", argv[1]); 379298178Sdelphij 380298178Sdelphij printdata(0, p, 0, l); 381298178Sdelphij munmap(p, l); 382298178Sdelphij return 0; 383298178Sdelphij} 384298178Sdelphij#endif 385