LCOV - code coverage report
Current view: top level - src - ber-help.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 126 220 57.3 %
Date: 2017-03-02 16:39:06 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /* ber-help.c - BER herlper functions
       2             :  *      Copyright (C) 2001, 2012 g10 Code GmbH
       3             :  *
       4             :  * This file is part of KSBA.
       5             :  *
       6             :  * KSBA is free software; you can redistribute it and/or modify
       7             :  * it under the terms of either
       8             :  *
       9             :  *   - the GNU Lesser General Public License as published by the Free
      10             :  *     Software Foundation; either version 3 of the License, or (at
      11             :  *     your option) any later version.
      12             :  *
      13             :  * or
      14             :  *
      15             :  *   - the GNU General Public License as published by the Free
      16             :  *     Software Foundation; either version 2 of the License, or (at
      17             :  *     your option) any later version.
      18             :  *
      19             :  * or both in parallel, as here.
      20             :  *
      21             :  * KSBA is distributed in the hope that it will be useful, but WITHOUT
      22             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      23             :  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      24             :  * License for more details.
      25             :  *
      26             :  * You should have received a copies of the GNU General Public License
      27             :  * and the GNU Lesser General Public License along with this program;
      28             :  * if not, see <http://www.gnu.org/licenses/>.
      29             :  */
      30             : 
      31             : #include <config.h>
      32             : #include <stdio.h>
      33             : #include <stdlib.h>
      34             : #include <string.h>
      35             : #include <assert.h>
      36             : #include "util.h"
      37             : 
      38             : #include "asn1-func.h" /* need some constants */
      39             : #include "ber-help.h"
      40             : 
      41             : /* Fixme: The parser functions should check that primitive types don't
      42             :    have the constructed bit set (which is not allowed).  This saves us
      43             :    some work when using these parsers */
      44             : 
      45             : static int
      46         794 : read_byte (ksba_reader_t reader)
      47             : {
      48             :   unsigned char buf;
      49             :   size_t nread;
      50             :   int rc;
      51             : 
      52             :   do
      53         794 :     rc = ksba_reader_read (reader, &buf, 1, &nread);
      54         794 :   while (!rc && !nread);
      55         794 :   return rc? -1: buf;
      56             : }
      57             : 
      58             : 
      59             : static int
      60           0 : premature_eof (struct tag_info *ti)
      61             : {
      62             :   /* Note: We do an strcmp on this string at othyer places. */
      63           0 :   ti->err_string = "premature EOF";
      64           0 :   return gpg_error (GPG_ERR_BAD_BER);
      65             : }
      66             : 
      67             : 
      68             : 
      69             : static gpg_error_t
      70           8 : eof_or_error (ksba_reader_t reader, struct tag_info *ti, int premature)
      71             : {
      72             :   gpg_error_t err;
      73             : 
      74           8 :   err = ksba_reader_error (reader);
      75           8 :   if (err)
      76             :     {
      77           0 :       ti->err_string = "read error";
      78           0 :       return err;
      79             :     }
      80           8 :   if (premature)
      81           0 :     return premature_eof (ti);
      82             : 
      83           8 :   return gpg_error (GPG_ERR_EOF);
      84             : }
      85             : 
      86             : 
      87             : 
      88             : /*
      89             :    Read the tag and the length part from the TLV triplet.
      90             :  */
      91             : gpg_error_t
      92         374 : _ksba_ber_read_tl (ksba_reader_t reader, struct tag_info *ti)
      93             : {
      94             :   int c;
      95             :   unsigned long tag;
      96             : 
      97         374 :   ti->length = 0;
      98         374 :   ti->ndef = 0;
      99         374 :   ti->nhdr = 0;
     100         374 :   ti->err_string = NULL;
     101         374 :   ti->non_der = 0;
     102             : 
     103             :   /* Get the tag */
     104         374 :   c = read_byte (reader);
     105         374 :   if (c==-1)
     106           8 :     return eof_or_error (reader, ti, 0);
     107             : 
     108         366 :   ti->buf[ti->nhdr++] = c;
     109         366 :   ti->class = (c & 0xc0) >> 6;
     110         366 :   ti->is_constructed = !!(c & 0x20);
     111         366 :   tag = c & 0x1f;
     112             : 
     113         366 :   if (tag == 0x1f)
     114             :     {
     115           0 :       tag = 0;
     116             :       do
     117             :         {
     118             :           /* We silently ignore an overflow in the tag value.  It is
     119             :              not worth checking for it. */
     120           0 :           tag <<= 7;
     121           0 :           c = read_byte (reader);
     122           0 :           if (c == -1)
     123           0 :             return eof_or_error (reader, ti, 1);
     124           0 :           if (ti->nhdr >= DIM (ti->buf))
     125             :             {
     126           0 :               ti->err_string = "tag+length header too large";
     127           0 :               return gpg_error (GPG_ERR_BAD_BER);
     128             :             }
     129           0 :           ti->buf[ti->nhdr++] = c;
     130           0 :           tag |= c & 0x7f;
     131             :         }
     132           0 :       while (c & 0x80);
     133             :     }
     134         366 :   ti->tag = tag;
     135             : 
     136             :   /* Get the length */
     137         366 :   c = read_byte (reader);
     138         366 :   if (c == -1)
     139           0 :     return eof_or_error (reader, ti, 1);
     140         366 :   if (ti->nhdr >= DIM (ti->buf))
     141             :     {
     142           0 :       ti->err_string = "tag+length header too large";
     143           0 :       return gpg_error (GPG_ERR_BAD_BER);
     144             :     }
     145         366 :   ti->buf[ti->nhdr++] = c;
     146             : 
     147         366 :   if ( !(c & 0x80) )
     148         333 :     ti->length = c;
     149          33 :   else if (c == 0x80)
     150             :     {
     151           0 :       ti->ndef = 1;
     152           0 :       ti->non_der = 1;
     153             :     }
     154          33 :   else if (c == 0xff)
     155             :     {
     156           0 :       ti->err_string = "forbidden length value";
     157           0 :       return gpg_error (GPG_ERR_BAD_BER);
     158             :     }
     159             :   else
     160             :     {
     161          33 :       unsigned long len = 0;
     162          33 :       int count = c & 0x7f;
     163             : 
     164          33 :       if (count > sizeof (len) || count > sizeof (size_t))
     165           0 :         return gpg_error (GPG_ERR_BAD_BER);
     166             : 
     167          87 :       for (; count; count--)
     168             :         {
     169          54 :           len <<= 8;
     170          54 :           c = read_byte (reader);
     171          54 :           if (c == -1)
     172           0 :             return eof_or_error (reader, ti, 1);
     173          54 :           if (ti->nhdr >= DIM (ti->buf))
     174             :             {
     175           0 :               ti->err_string = "tag+length header too large";
     176           0 :               return gpg_error (GPG_ERR_BAD_BER);
     177             :             }
     178          54 :           ti->buf[ti->nhdr++] = c;
     179          54 :           len |= c & 0xff;
     180             :         }
     181          33 :       ti->length = len;
     182             :     }
     183             : 
     184             :   /* Without this kludge some example certs can't be parsed */
     185         366 :   if (ti->class == CLASS_UNIVERSAL && !ti->tag)
     186           0 :     ti->length = 0;
     187             : 
     188         366 :   return 0;
     189             : }
     190             : 
     191             : /*
     192             :    Parse the buffer at the address BUFFER which of SIZE and return
     193             :    the tag and the length part from the TLV triplet.  Update BUFFER
     194             :    and SIZE on success. */
     195             : gpg_error_t
     196         100 : _ksba_ber_parse_tl (unsigned char const **buffer, size_t *size,
     197             :                     struct tag_info *ti)
     198             : {
     199             :   int c;
     200             :   unsigned long tag;
     201         100 :   const unsigned char *buf = *buffer;
     202         100 :   size_t length = *size;
     203             : 
     204         100 :   ti->length = 0;
     205         100 :   ti->ndef = 0;
     206         100 :   ti->nhdr = 0;
     207         100 :   ti->err_string = NULL;
     208         100 :   ti->non_der = 0;
     209             : 
     210             :   /* Get the tag */
     211         100 :   if (!length)
     212           0 :     return premature_eof (ti);
     213         100 :   c = *buf++; length--;
     214             : 
     215         100 :   ti->buf[ti->nhdr++] = c;
     216         100 :   ti->class = (c & 0xc0) >> 6;
     217         100 :   ti->is_constructed = !!(c & 0x20);
     218         100 :   tag = c & 0x1f;
     219             : 
     220         100 :   if (tag == 0x1f)
     221             :     {
     222           0 :       tag = 0;
     223             :       do
     224             :         {
     225             :           /* We silently ignore an overflow in the tag value.  It is
     226             :              not worth checking for it. */
     227           0 :           tag <<= 7;
     228           0 :           if (!length)
     229           0 :             return premature_eof (ti);
     230           0 :           c = *buf++; length--;
     231           0 :           if (ti->nhdr >= DIM (ti->buf))
     232             :             {
     233           0 :               ti->err_string = "tag+length header too large";
     234           0 :               return gpg_error (GPG_ERR_BAD_BER);
     235             :             }
     236           0 :           ti->buf[ti->nhdr++] = c;
     237           0 :           tag |= c & 0x7f;
     238             :         }
     239           0 :       while (c & 0x80);
     240             :     }
     241         100 :   ti->tag = tag;
     242             : 
     243             :   /* Get the length */
     244         100 :   if (!length)
     245           0 :     return premature_eof (ti);
     246         100 :   c = *buf++; length--;
     247         100 :   if (ti->nhdr >= DIM (ti->buf))
     248             :     {
     249           0 :       ti->err_string = "tag+length header too large";
     250           0 :       return gpg_error (GPG_ERR_BAD_BER);
     251             :     }
     252         100 :   ti->buf[ti->nhdr++] = c;
     253             : 
     254         100 :   if ( !(c & 0x80) )
     255          99 :     ti->length = c;
     256           1 :   else if (c == 0x80)
     257             :     {
     258           0 :       ti->ndef = 1;
     259           0 :       ti->non_der = 1;
     260             :     }
     261           1 :   else if (c == 0xff)
     262             :     {
     263           0 :       ti->err_string = "forbidden length value";
     264           0 :       return gpg_error (GPG_ERR_BAD_BER);
     265             :     }
     266             :   else
     267             :     {
     268           1 :       unsigned long len = 0;
     269           1 :       int count = c & 0x7f;
     270             : 
     271           1 :       if (count > sizeof (len) || count > sizeof (size_t))
     272           0 :         return gpg_error (GPG_ERR_BAD_BER);
     273             : 
     274           2 :       for (; count; count--)
     275             :         {
     276           1 :           len <<= 8;
     277           1 :           if (!length)
     278           0 :             return premature_eof (ti);
     279           1 :           c = *buf++; length--;
     280           1 :           if (ti->nhdr >= DIM (ti->buf))
     281             :             {
     282           0 :               ti->err_string = "tag+length header too large";
     283           0 :               return gpg_error (GPG_ERR_BAD_BER);
     284             :             }
     285           1 :           ti->buf[ti->nhdr++] = c;
     286           1 :           len |= c & 0xff;
     287             :         }
     288             :       /* Sanity check for the length: This is done so that we can take
     289             :        * the value for malloc plus some additional bytes without
     290             :        * risking an overflow.  */
     291           1 :       if (len > (1 << 30))
     292           0 :         return gpg_error (GPG_ERR_BAD_BER);
     293           1 :       ti->length = len;
     294             :     }
     295             : 
     296             : 
     297             :   /* Without this kludge some example certs can't be parsed */
     298         100 :   if (ti->class == CLASS_UNIVERSAL && !ti->tag)
     299           0 :     ti->length = 0;
     300             : 
     301         100 :   *buffer = buf;
     302         100 :   *size = length;
     303         100 :   return 0;
     304             : }
     305             : 
     306             : 
     307             : /* Write TAG of CLASS to WRITER.  constructed is a flag telling
     308             :    whether the value is a constructed one.  length gives the length of
     309             :    the value, if it is 0 undefinite length is assumed.  length is
     310             :    ignored for the NULL tag. */
     311             : gpg_error_t
     312         109 : _ksba_ber_write_tl (ksba_writer_t writer,
     313             :                     unsigned long tag,
     314             :                     enum tag_class class,
     315             :                     int constructed,
     316             :                     unsigned long length)
     317             : {
     318             :   unsigned char buf[50];
     319         109 :   int buflen = 0;
     320             : 
     321         109 :   if (tag < 0x1f)
     322             :     {
     323         109 :       *buf = (class << 6) | tag;
     324         109 :       if (constructed)
     325          51 :         *buf |= 0x20;
     326         109 :       buflen++;
     327             :     }
     328             :   else
     329             :     {
     330           0 :       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     331             :     }
     332             : 
     333         109 :   if (!tag && !class)
     334           0 :     buf[buflen++] = 0; /* end tag */
     335         109 :   else if (tag == TYPE_NULL && !class)
     336           6 :     buf[buflen++] = 0; /* NULL tag */
     337         103 :   else if (!length)
     338           0 :     buf[buflen++] = 0x80; /* indefinite length */
     339         103 :   else if (length < 128)
     340          79 :     buf[buflen++] = length;
     341             :   else
     342             :     {
     343             :       int i;
     344             : 
     345             :       /* fixme: if we know the sizeof an ulong we could support larger
     346             :          objects - however this is pretty ridiculous */
     347          40 :       i = (length <= 0xff ? 1:
     348          16 :            length <= 0xffff ? 2:
     349           0 :            length <= 0xffffff ? 3: 4);
     350             : 
     351          24 :       buf[buflen++] = (0x80 | i);
     352          24 :       if (i > 3)
     353           0 :         buf[buflen++] = length >> 24;
     354          24 :       if (i > 2)
     355           0 :         buf[buflen++] = length >> 16;
     356          24 :       if (i > 1)
     357          16 :         buf[buflen++] = length >> 8;
     358          24 :       buf[buflen++] = length;
     359             :     }
     360             : 
     361         109 :   return ksba_writer_write (writer, buf, buflen);
     362             : }
     363             : 
     364             : /* Encode TAG of CLASS in BUFFER.  CONSTRUCTED is a flag telling
     365             :    whether the value is a constructed one.  LENGTH gives the length of
     366             :    the value, if it is 0 undefinite length is assumed.  LENGTH is
     367             :    ignored for the NULL tag. It is assumed that the provide buffer is
     368             :    large enough for storing the result - this is usually achieved by
     369             :    using _ksba_ber_count_tl() in advance.  Returns 0 in case of an
     370             :    error or the length of the encoding.*/
     371             : size_t
     372           0 : _ksba_ber_encode_tl (unsigned char *buffer,
     373             :                      unsigned long tag,
     374             :                      enum tag_class class,
     375             :                      int constructed,
     376             :                      unsigned long length)
     377             : {
     378           0 :   unsigned char *buf = buffer;
     379             : 
     380           0 :   if (tag < 0x1f)
     381             :     {
     382           0 :       *buf = (class << 6) | tag;
     383           0 :       if (constructed)
     384           0 :         *buf |= 0x20;
     385           0 :       buf++;
     386             :     }
     387             :   else
     388             :     {
     389           0 :       return 0; /*Not implemented*/
     390             :     }
     391             : 
     392           0 :   if (!tag && !class)
     393           0 :     *buf++ = 0; /* end tag */
     394           0 :   else if (tag == TYPE_NULL && !class)
     395           0 :     *buf++ = 0; /* NULL tag */
     396           0 :   else if (!length)
     397           0 :     *buf++ = 0x80; /* indefinite length */
     398           0 :   else if (length < 128)
     399           0 :     *buf++ = length;
     400             :   else
     401             :     {
     402             :       int i;
     403             : 
     404             :       /* fixme: if we know the sizeof an ulong we could support larger
     405             :          objetcs - however this is pretty ridiculous */
     406           0 :       i = (length <= 0xff ? 1:
     407           0 :            length <= 0xffff ? 2:
     408           0 :            length <= 0xffffff ? 3: 4);
     409             : 
     410           0 :       *buf++ = (0x80 | i);
     411           0 :       if (i > 3)
     412           0 :         *buf++ = length >> 24;
     413           0 :       if (i > 2)
     414           0 :         *buf++ = length >> 16;
     415           0 :       if (i > 1)
     416           0 :         *buf++ = length >> 8;
     417           0 :       *buf++ = length;
     418             :     }
     419             : 
     420           0 :   return buf - buffer;
     421             : }
     422             : 
     423             : 
     424             : /* Calculate the length of the TL needed to encode a TAG of CLASS.
     425             :    CONSTRUCTED is a flag telling whether the value is a constructed
     426             :    one.  LENGTH gives the length of the value; if it is 0 an
     427             :    indefinite length is assumed.  LENGTH is ignored for the NULL
     428             :    tag. */
     429             : size_t
     430          78 : _ksba_ber_count_tl (unsigned long tag,
     431             :                     enum tag_class class,
     432             :                     int constructed,
     433             :                     unsigned long length)
     434             : {
     435          78 :   int buflen = 0;
     436             : 
     437             :   (void)constructed;  /* Not used, but passed for uniformity of such calls.  */
     438             : 
     439          78 :   if (tag < 0x1f)
     440             :     {
     441          78 :       buflen++;
     442             :     }
     443             :   else
     444             :     {
     445           0 :       buflen++; /* assume one and let the actual write function bail out */
     446             :     }
     447             : 
     448          78 :   if (!tag && !class)
     449           0 :     buflen++; /* end tag */
     450          78 :   else if (tag == TYPE_NULL && !class)
     451           6 :     buflen++; /* NULL tag */
     452          72 :   else if (!length)
     453           0 :     buflen++; /* indefinite length */
     454          72 :   else if (length < 128)
     455          60 :     buflen++;
     456             :   else
     457             :     {
     458             :       int i;
     459             : 
     460             :       /* fixme: if we know the sizeof an ulong we could support larger
     461             :          objetcs - however this is pretty ridiculous */
     462          20 :       i = (length <= 0xff ? 1:
     463           8 :            length <= 0xffff ? 2:
     464           0 :            length <= 0xffffff ? 3: 4);
     465             : 
     466          12 :       buflen++;
     467          12 :       if (i > 3)
     468           0 :         buflen++;
     469          12 :       if (i > 2)
     470           0 :         buflen++;
     471          12 :       if (i > 1)
     472           8 :         buflen++;
     473          12 :       buflen++;
     474             :     }
     475             : 
     476          78 :   return buflen;
     477             : }

Generated by: LCOV version 1.13