"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/der.c" (15 Oct 2018, 10006 Bytes) of package /linux/misc/file-5.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "der.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

    1 /*-
    2  * Copyright (c) 2016 Christos Zoulas
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   15  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   16  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   24  * POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 /*
   27  * DER (Distinguished Encoding Rules) Parser
   28  *
   29  * Sources:
   30  * https://en.wikipedia.org/wiki/X.690
   31  * http://fm4dd.com/openssl/certexamples.htm
   32  * http://blog.engelke.com/2014/10/17/parsing-ber-and-der-encoded-asn-1-objects/
   33  */
   34 #ifndef TEST_DER
   35 #include "file.h"
   36 
   37 #ifndef lint
   38 FILE_RCSID("@(#)$File: der.c,v 1.15 2018/10/15 16:29:16 christos Exp $")
   39 #endif
   40 #endif
   41 
   42 #include <sys/types.h>
   43 
   44 #include <stdio.h>
   45 #include <fcntl.h>
   46 #include <stdlib.h>
   47 #include <string.h>
   48 #include <ctype.h>
   49 
   50 #ifndef TEST_DER
   51 #include "magic.h"
   52 #include "der.h"
   53 #else
   54 #include <sys/mman.h>
   55 #include <sys/stat.h>
   56 #include <err.h>
   57 #endif
   58 
   59 #define DER_BAD ((uint32_t)-1)
   60 
   61 #define DER_CLASS_UNIVERSAL 0
   62 #define DER_CLASS_APPLICATION   1
   63 #define DER_CLASS_CONTEXT   2
   64 #define DER_CLASS_PRIVATE   3
   65 #ifdef DEBUG_DER
   66 static const char der_class[] = "UACP";
   67 #endif
   68 
   69 #define DER_TYPE_PRIMITIVE  0
   70 #define DER_TYPE_CONSTRUCTED    1
   71 #ifdef DEBUG_DER
   72 static const char der_type[] = "PC";
   73 #endif
   74 
   75 #define DER_TAG_EOC         0x00
   76 #define DER_TAG_BOOLEAN         0x01
   77 #define DER_TAG_INTEGER         0x02
   78 #define DER_TAG_BIT STRING      0x03
   79 #define DER_TAG_OCTET_STRING        0x04
   80 #define DER_TAG_NULL            0x05
   81 #define DER_TAG_OBJECT_IDENTIFIER   0x06
   82 #define DER_TAG_OBJECT_DESCRIPTOR   0x07
   83 #define DER_TAG_EXTERNAL        0x08
   84 #define DER_TAG_REAL            0x09
   85 #define DER_TAG_ENUMERATED      0x0a
   86 #define DER_TAG_EMBEDDED_PDV        0x0b
   87 #define DER_TAG_UTF8_STRING     0x0c
   88 #define DER_TAG_RELATIVE_OID        0x0d
   89 #define DER_TAG_RESERVED_1      0x0e
   90 #define DER_TAG_RESERVED_2      0x0f
   91 #define DER_TAG_SEQUENCE        0x10
   92 #define DER_TAG_SET         0x11
   93 #define DER_TAG_NUMERIC_STRING      0x12
   94 #define DER_TAG_PRINTABLE_STRING    0x13
   95 #define DER_TAG_T61_STRING      0x14
   96 #define DER_TAG_VIDEOTEX_STRING     0x15
   97 #define DER_TAG_IA5_STRING      0x16
   98 #define DER_TAG_UTCTIME         0x17
   99 #define DER_TAG_GENERALIZED_TIME    0x18
  100 #define DER_TAG_GRAPHIC_STRING      0x19
  101 #define DER_TAG_VISIBLE_STRING      0x1a
  102 #define DER_TAG_GENERAL_STRING      0x1b
  103 #define DER_TAG_UNIVERSAL_STRING    0x1c
  104 #define DER_TAG_CHARACTER_STRING    0x1d
  105 #define DER_TAG_BMP_STRING      0x1e
  106 #define DER_TAG_LONG            0x1f
  107 
  108 static const char *der__tag[] = {
  109     "eoc", "bool", "int", "bit_str", "octet_str",
  110     "null", "obj_id", "obj_desc", "ext", "real",
  111     "enum", "embed", "utf8_str", "oid", "res1",
  112     "res2", "seq", "set", "num_str", "prt_str",
  113     "t61_str", "vid_str", "ia5_str", "utc_time",
  114     "gen_time", "gr_str", "vis_str", "gen_str",
  115     "char_str", "bmp_str", "long"
  116 };
  117 
  118 #ifdef DEBUG_DER
  119 #define DPRINTF(a) printf a
  120 #else
  121 #define DPRINTF(a)
  122 #endif
  123 
  124 #ifdef TEST_DER
  125 static uint8_t
  126 getclass(uint8_t c)
  127 {
  128     return c >> 6;
  129 }
  130 
  131 static uint8_t
  132 gettype(uint8_t c)
  133 {
  134     return (c >> 5) & 1;
  135 }
  136 #endif
  137 
  138 static uint32_t
  139 gettag(const uint8_t *c, size_t *p, size_t l)
  140 {
  141     uint32_t tag;
  142 
  143     if (*p >= l)
  144         return DER_BAD;
  145 
  146     tag = c[(*p)++] & 0x1f;
  147 
  148     if (tag != 0x1f)
  149         return tag;
  150 
  151     if (*p >= l)
  152         return DER_BAD;
  153 
  154     while (c[*p] >= 0x80) {
  155         tag = tag * 128 + c[(*p)++] - 0x80;
  156         if (*p >= l)
  157             return DER_BAD;
  158     }
  159     return tag;
  160 }
  161 
  162 /*
  163  * Read the length of a DER tag from the input.
  164  *
  165  * `c` is the input, `p` is an output parameter that specifies how much of the
  166  * input we consumed, and `l` is the maximum input length.
  167  *
  168  * Returns the length, or DER_BAD if the end of the input is reached or the
  169  * length exceeds the remaining input.
  170  */
  171 static uint32_t
  172 getlength(const uint8_t *c, size_t *p, size_t l)
  173 {
  174     uint8_t digits, i;
  175     size_t len;
  176     int is_onebyte_result;
  177 
  178     if (*p >= l)
  179         return DER_BAD;
  180 
  181     /*
  182      * Digits can either be 0b0 followed by the result, or 0b1
  183      * followed by the number of digits of the result. In either case,
  184      * we verify that we can read so many bytes from the input.
  185      */
  186     is_onebyte_result = (c[*p] & 0x80) == 0;
  187     digits = c[(*p)++] & 0x7f;
  188     if (*p + digits >= l)
  189         return DER_BAD;
  190 
  191     if (is_onebyte_result)
  192         return digits;
  193 
  194     /*
  195      * Decode len. We've already verified that we're allowed to read
  196      * `digits` bytes.
  197      */
  198     len = 0;
  199     for (i = 0; i < digits; i++)
  200         len = (len << 8) | c[(*p)++];
  201 
  202     if (len > UINT32_MAX - *p || *p + len >= l)
  203         return DER_BAD;
  204     return CAST(uint32_t, len);
  205 }
  206 
  207 static const char *
  208 der_tag(char *buf, size_t len, uint32_t tag)
  209 {
  210     if (tag < DER_TAG_LONG)
  211         strlcpy(buf, der__tag[tag], len);
  212     else
  213         snprintf(buf, len, "%#x", tag);
  214     return buf;
  215 }
  216 
  217 #ifndef TEST_DER
  218 static int
  219 der_data(char *buf, size_t blen, uint32_t tag, const void *q, uint32_t len)
  220 {
  221     const uint8_t *d = CAST(const uint8_t *, q);
  222     switch (tag) {
  223     case DER_TAG_PRINTABLE_STRING:
  224     case DER_TAG_UTF8_STRING:
  225     case DER_TAG_IA5_STRING:
  226     case DER_TAG_UTCTIME:
  227         return snprintf(buf, blen, "%.*s", len, (const char *)q);
  228     default:
  229         break;
  230     }
  231 
  232     for (uint32_t i = 0; i < len; i++) {
  233         uint32_t z = i << 1;
  234         if (z < blen - 2)
  235             snprintf(buf + z, blen - z, "%.2x", d[i]);
  236     }
  237     return len * 2;
  238 }
  239 
  240 int32_t
  241 der_offs(struct magic_set *ms, struct magic *m, size_t nbytes)
  242 {
  243     const uint8_t *b = RCAST(const uint8_t *, ms->search.s);
  244     size_t offs = 0, len = ms->search.s_len ? ms->search.s_len : nbytes;
  245 
  246     if (gettag(b, &offs, len) == DER_BAD)
  247         return -1;
  248     DPRINTF(("%s1: %d %" SIZE_T_FORMAT "u %u\n", __func__, ms->offset,
  249         offs, m->offset));
  250 
  251     uint32_t tlen = getlength(b, &offs, len);
  252     if (tlen == DER_BAD)
  253         return -1;
  254     DPRINTF(("%s2: %d %" SIZE_T_FORMAT "u %u\n", __func__, ms->offset,
  255         offs, tlen));
  256 
  257     offs += ms->offset + m->offset;
  258     DPRINTF(("cont_level = %d\n", m->cont_level));
  259 #ifdef DEBUG_DER
  260     for (size_t i = 0; i < m->cont_level; i++)
  261         printf("cont_level[%" SIZE_T_FORMAT "u] = %u\n", i,
  262             ms->c.li[i].off);
  263 #endif
  264     if (m->cont_level != 0) {
  265         if (offs + tlen > nbytes)
  266             return -1;
  267         ms->c.li[m->cont_level - 1].off = CAST(int, offs + tlen);
  268         DPRINTF(("cont_level[%u] = %u\n", m->cont_level - 1,
  269             ms->c.li[m->cont_level - 1].off));
  270     }
  271     return CAST(int32_t, offs);
  272 }
  273 
  274 int
  275 der_cmp(struct magic_set *ms, struct magic *m)
  276 {
  277     const uint8_t *b = RCAST(const uint8_t *, ms->search.s);
  278     const char *s = m->value.s;
  279     size_t offs = 0, len = ms->search.s_len;
  280     uint32_t tag, tlen;
  281     char buf[128];
  282 
  283     tag = gettag(b, &offs, len);
  284     if (tag == DER_BAD)
  285         return -1;
  286 
  287     tlen = getlength(b, &offs, len);
  288     if (tlen == DER_BAD)
  289         return -1;
  290 
  291     der_tag(buf, sizeof(buf), tag);
  292     if ((ms->flags & MAGIC_DEBUG) != 0)
  293         fprintf(stderr, "%s: tag %p got=%s exp=%s\n", __func__, b,
  294             buf, s);
  295     size_t slen = strlen(buf);
  296 
  297     if (strncmp(buf, s, slen) != 0)
  298         return 0;
  299 
  300     s += slen;
  301 
  302 again:
  303     switch (*s) {
  304     case '\0':
  305         return 1;
  306     case '=':
  307         s++;
  308         goto val;
  309     default:
  310         if (!isdigit((unsigned char)*s))
  311             return 0;
  312 
  313         slen = 0;
  314         do
  315             slen = slen * 10 + *s - '0';
  316         while (isdigit((unsigned char)*++s));
  317         if ((ms->flags & MAGIC_DEBUG) != 0)
  318             fprintf(stderr, "%s: len %" SIZE_T_FORMAT "u %u\n",
  319                 __func__, slen, tlen);
  320         if (tlen != slen)
  321             return 0;
  322         goto again;
  323     }
  324 val:
  325     DPRINTF(("%s: before data %" SIZE_T_FORMAT "u %u\n", __func__, offs,
  326         tlen));
  327     der_data(buf, sizeof(buf), tag, b + offs, tlen);
  328     if ((ms->flags & MAGIC_DEBUG) != 0)
  329         fprintf(stderr, "%s: data %s %s\n", __func__, buf, s);
  330     if (strcmp(buf, s) != 0 && strcmp("x", s) != 0)
  331         return 0;
  332     strlcpy(ms->ms_value.s, buf, sizeof(ms->ms_value.s));
  333     return 1;
  334 }
  335 #endif
  336 
  337 #ifdef TEST_DER
  338 static void
  339 printtag(uint32_t tag, const void *q, uint32_t len)
  340 {
  341     const uint8_t *d = q;
  342     switch (tag) {
  343     case DER_TAG_PRINTABLE_STRING:
  344     case DER_TAG_UTF8_STRING:
  345         printf("%.*s\n", len, (const char *)q);
  346         return;
  347     default:
  348         break;
  349     }
  350 
  351     for (uint32_t i = 0; i < len; i++)
  352         printf("%.2x", d[i]);
  353     printf("\n");
  354 }
  355 
  356 static void
  357 printdata(size_t level, const void *v, size_t x, size_t l)
  358 {
  359     const uint8_t *p = v, *ep = p + l;
  360     size_t ox;
  361     char buf[128];
  362 
  363     while (p + x < ep) {
  364         const uint8_t *q;
  365         uint8_t c = getclass(p[x]);
  366         uint8_t t = gettype(p[x]);
  367         ox = x;
  368         if (x != 0)
  369         printf("%.2x %.2x %.2x\n", p[x - 1], p[x], p[x + 1]);
  370         uint32_t tag = gettag(p, &x, ep - p + x);
  371         if (p + x >= ep)
  372             break;
  373         uint32_t len = getlength(p, &x, ep - p + x);
  374 
  375         printf("%" SIZE_T_FORMAT "u %" SIZE_T_FORMAT "u-%"
  376             SIZE_T_FORMAT "u %c,%c,%s,%u:", level, ox, x,
  377             der_class[c], der_type[t],
  378             der_tag(buf, sizeof(buf), tag), len);
  379         q = p + x;
  380         if (p + len > ep)
  381             errx(EXIT_FAILURE, "corrupt der");
  382         printtag(tag, q, len);
  383         if (t != DER_TYPE_PRIMITIVE)
  384             printdata(level + 1, p, x, len + x);
  385         x += len;
  386     }
  387 }
  388 
  389 int
  390 main(int argc, char *argv[])
  391 {
  392     int fd;
  393     struct stat st;
  394     size_t l;
  395     void *p;
  396 
  397     if ((fd = open(argv[1], O_RDONLY)) == -1)
  398         err(EXIT_FAILURE, "open `%s'", argv[1]);
  399     if (fstat(fd, &st) == -1)
  400         err(EXIT_FAILURE, "stat `%s'", argv[1]);
  401     l = (size_t)st.st_size;
  402     if ((p = mmap(NULL, l, PROT_READ, MAP_FILE, fd, 0)) == MAP_FAILED)
  403         err(EXIT_FAILURE, "mmap `%s'", argv[1]);
  404 
  405     printdata(0, p, 0, l);
  406     munmap(p, l);
  407     return 0;
  408 }
  409 #endif