LCOV - code coverage report
Current view: top level - common - tlv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 32 135 23.7 %
Date: 2015-11-05 17:10:59 Functions: 1 5 20.0 %

          Line data    Source code
       1             : /* tlv.c - Tag-Length-Value Utilities
       2             :  *      Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * This file 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             :  * This file is distributed in the hope that it will be useful,
      22             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24             :  * GNU General Public License for more details.
      25             :  *
      26             :  * You should have received a copy of the GNU General Public License
      27             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      28             :  */
      29             : 
      30             : #include <config.h>
      31             : 
      32             : #include <stdio.h>
      33             : #include <stdlib.h>
      34             : #include <string.h>
      35             : #include <assert.h>
      36             : 
      37             : #if GNUPG_MAJOR_VERSION == 1
      38             : #define GPG_ERR_EOF               (-1)
      39             : #define GPG_ERR_BAD_BER           (1)  /*G10ERR_GENERAL*/
      40             : #define GPG_ERR_INV_SEXP          (45) /*G10ERR_INV_ARG*/
      41             : typedef int gpg_error_t;
      42             : #define gpg_make_err(x,n) (n)
      43             : #else
      44             : #include <gpg-error.h>
      45             : #endif
      46             : 
      47             : #include "util.h"
      48             : #include "tlv.h"
      49             : 
      50             : static const unsigned char *
      51           0 : do_find_tlv (const unsigned char *buffer, size_t length,
      52             :              int tag, size_t *nbytes, int nestlevel)
      53             : {
      54           0 :   const unsigned char *s = buffer;
      55           0 :   size_t n = length;
      56             :   size_t len;
      57             :   int this_tag;
      58             :   int composite;
      59             : 
      60             :   for (;;)
      61             :     {
      62           0 :       buffer = s;
      63           0 :       if (n < 2)
      64           0 :         return NULL; /* Buffer definitely too short for tag and length. */
      65           0 :       if (!*s || *s == 0xff)
      66             :         { /* Skip optional filler between TLV objects. */
      67           0 :           s++;
      68           0 :           n--;
      69           0 :           continue;
      70             :         }
      71           0 :       composite = !!(*s & 0x20);
      72           0 :       if ((*s & 0x1f) == 0x1f)
      73             :         { /* more tag bytes to follow */
      74           0 :           s++;
      75           0 :           n--;
      76           0 :           if (n < 2)
      77           0 :             return NULL; /* buffer definitely too short for tag and length. */
      78           0 :           if ((*s & 0x1f) == 0x1f)
      79           0 :             return NULL; /* We support only up to 2 bytes. */
      80           0 :           this_tag = (s[-1] << 8) | (s[0] & 0x7f);
      81             :         }
      82             :       else
      83           0 :         this_tag = s[0];
      84           0 :       len = s[1];
      85           0 :       s += 2; n -= 2;
      86           0 :       if (len < 0x80)
      87             :         ;
      88           0 :       else if (len == 0x81)
      89             :         { /* One byte length follows. */
      90           0 :           if (!n)
      91           0 :             return NULL; /* we expected 1 more bytes with the length. */
      92           0 :           len = s[0];
      93           0 :           s++; n--;
      94             :         }
      95           0 :       else if (len == 0x82)
      96             :         { /* Two byte length follows. */
      97           0 :           if (n < 2)
      98           0 :             return NULL; /* We expected 2 more bytes with the length. */
      99           0 :           len = ((size_t)s[0] << 8) | s[1];
     100           0 :           s += 2; n -= 2;
     101             :         }
     102             :       else
     103           0 :         return NULL; /* APDU limit is 65535, thus it does not make
     104             :                         sense to assume longer length fields. */
     105             : 
     106           0 :       if (composite && nestlevel < 100)
     107             :         { /* Dive into this composite DO after checking for a too deep
     108             :              nesting. */
     109             :           const unsigned char *tmp_s;
     110             :           size_t tmp_len;
     111             : 
     112           0 :           tmp_s = do_find_tlv (s, len, tag, &tmp_len, nestlevel+1);
     113           0 :           if (tmp_s)
     114             :             {
     115           0 :               *nbytes = tmp_len;
     116           0 :               return tmp_s;
     117             :             }
     118             :         }
     119             : 
     120           0 :       if (this_tag == tag)
     121             :         {
     122           0 :           *nbytes = len;
     123           0 :           return s;
     124             :         }
     125           0 :       if (len > n)
     126           0 :         return NULL; /* Buffer too short to skip to the next tag. */
     127           0 :       s += len; n -= len;
     128           0 :     }
     129             : }
     130             : 
     131             : 
     132             : /* Locate a TLV encoded data object in BUFFER of LENGTH and
     133             :    return a pointer to value as well as its length in NBYTES.  Return
     134             :    NULL if it was not found or if the object does not fit into the buffer. */
     135             : const unsigned char *
     136           0 : find_tlv (const unsigned char *buffer, size_t length,
     137             :           int tag, size_t *nbytes)
     138             : {
     139             :   const unsigned char *p;
     140             : 
     141           0 :   p = do_find_tlv (buffer, length, tag, nbytes, 0);
     142           0 :   if (p && *nbytes > (length - (p-buffer)))
     143           0 :     p = NULL; /* Object longer than buffer. */
     144           0 :   return p;
     145             : }
     146             : 
     147             : 
     148             : 
     149             : /* Locate a TLV encoded data object in BUFFER of LENGTH and
     150             :    return a pointer to value as well as its length in NBYTES.  Return
     151             :    NULL if it was not found.  Note, that the function does not check
     152             :    whether the value fits into the provided buffer. */
     153             : const unsigned char *
     154           0 : find_tlv_unchecked (const unsigned char *buffer, size_t length,
     155             :                     int tag, size_t *nbytes)
     156             : {
     157           0 :   return do_find_tlv (buffer, length, tag, nbytes, 0);
     158             : }
     159             : 
     160             : 
     161             : /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
     162             :    and the length part from the TLV triplet.  Update BUFFER and SIZE
     163             :    on success. */
     164             : gpg_error_t
     165           0 : parse_ber_header (unsigned char const **buffer, size_t *size,
     166             :                   int *r_class, int *r_tag,
     167             :                   int *r_constructed, int *r_ndef,
     168             :                   size_t *r_length, size_t *r_nhdr)
     169             : {
     170             :   int c;
     171             :   unsigned long tag;
     172           0 :   const unsigned char *buf = *buffer;
     173           0 :   size_t length = *size;
     174             : 
     175           0 :   *r_ndef = 0;
     176           0 :   *r_length = 0;
     177           0 :   *r_nhdr = 0;
     178             : 
     179             :   /* Get the tag. */
     180           0 :   if (!length)
     181           0 :     return gpg_err_make (default_errsource, GPG_ERR_EOF);
     182           0 :   c = *buf++; length--; ++*r_nhdr;
     183             : 
     184           0 :   *r_class = (c & 0xc0) >> 6;
     185           0 :   *r_constructed = !!(c & 0x20);
     186           0 :   tag = c & 0x1f;
     187             : 
     188           0 :   if (tag == 0x1f)
     189             :     {
     190           0 :       tag = 0;
     191             :       do
     192             :         {
     193           0 :           tag <<= 7;
     194           0 :           if (!length)
     195           0 :             return gpg_err_make (default_errsource, GPG_ERR_EOF);
     196           0 :           c = *buf++; length--; ++*r_nhdr;
     197           0 :           tag |= c & 0x7f;
     198             : 
     199             :         }
     200           0 :       while (c & 0x80);
     201             :     }
     202           0 :   *r_tag = tag;
     203             : 
     204             :   /* Get the length. */
     205           0 :   if (!length)
     206           0 :     return gpg_err_make (default_errsource, GPG_ERR_EOF);
     207           0 :   c = *buf++; length--; ++*r_nhdr;
     208             : 
     209           0 :   if ( !(c & 0x80) )
     210           0 :     *r_length = c;
     211           0 :   else if (c == 0x80)
     212           0 :     *r_ndef = 1;
     213           0 :   else if (c == 0xff)
     214           0 :     return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
     215             :   else
     216             :     {
     217           0 :       unsigned long len = 0;
     218           0 :       int count = c & 0x7f;
     219             : 
     220           0 :       if (count > sizeof (len) || count > sizeof (size_t))
     221           0 :         return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
     222             : 
     223           0 :       for (; count; count--)
     224             :         {
     225           0 :           len <<= 8;
     226           0 :           if (!length)
     227           0 :             return gpg_err_make (default_errsource, GPG_ERR_EOF);
     228           0 :           c = *buf++; length--; ++*r_nhdr;
     229           0 :           len |= c & 0xff;
     230             :         }
     231           0 :       *r_length = len;
     232             :     }
     233             : 
     234             :   /* Without this kludge some example certs can't be parsed. */
     235           0 :   if (*r_class == CLASS_UNIVERSAL && !*r_tag)
     236           0 :     *r_length = 0;
     237             : 
     238           0 :   *buffer = buf;
     239           0 :   *size = length;
     240           0 :   return 0;
     241             : }
     242             : 
     243             : 
     244             : /* FIXME: The following function should not go into this file but for
     245             :    now it is easier to keep it here. */
     246             : 
     247             : /* Return the next token of an canonical encoded S-expression.  BUF
     248             :    is the pointer to the S-expression and BUFLEN is a pointer to the
     249             :    length of this S-expression (used to validate the syntax).  Both
     250             :    are updated to reflect the new position.  The token itself is
     251             :    returned as a pointer into the original buffer at TOK and TOKLEN.
     252             :    If a parentheses is the next token, TOK will be set to NULL.
     253             :    TOKLEN is checked to be within the bounds.  On error an error code
     254             :    is returned and no pointer is not guaranteed to point to
     255             :    a meaningful value.  DEPTH should be initialized to 0 and will
     256             :    reflect on return the actual depth of the tree. To detect the end
     257             :    of the S-expression it is advisable to check DEPTH after a
     258             :    successful return.
     259             : 
     260             :    depth = 0;
     261             :    while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
     262             :           && depth)
     263             :      process_token (tok, toklen);
     264             :    if (err)
     265             :      handle_error ();
     266             :  */
     267             : gpg_error_t
     268          39 : parse_sexp (unsigned char const **buf, size_t *buflen,
     269             :             int *depth, unsigned char const **tok, size_t *toklen)
     270             : {
     271             :   const unsigned char *s;
     272             :   size_t n, vlen;
     273             : 
     274          39 :   s = *buf;
     275          39 :   n = *buflen;
     276          39 :   *tok = NULL;
     277          39 :   *toklen = 0;
     278          39 :   if (!n)
     279           0 :     return *depth ? gpg_err_make (default_errsource, GPG_ERR_INV_SEXP) : 0;
     280          39 :   if (*s == '(')
     281             :     {
     282          12 :       s++; n--;
     283          12 :       (*depth)++;
     284          12 :       *buf = s;
     285          12 :       *buflen = n;
     286          12 :       return 0;
     287             :     }
     288          27 :   if (*s == ')')
     289             :     {
     290           9 :       if (!*depth)
     291           0 :         return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     292           9 :       *toklen = 1;
     293           9 :       s++; n--;
     294           9 :       (*depth)--;
     295           9 :       *buf = s;
     296           9 :       *buflen = n;
     297           9 :       return 0;
     298             :     }
     299          42 :   for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--)
     300          24 :     vlen = vlen*10 + (*s - '0');
     301          18 :   if (!n || *s != ':')
     302           0 :     return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     303          18 :   s++; n--;
     304          18 :   if (vlen > n)
     305           0 :     return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     306          18 :   *tok = s;
     307          18 :   *toklen = vlen;
     308          18 :   s += vlen;
     309          18 :   n -= vlen;
     310          18 :   *buf = s;
     311          18 :   *buflen = n;
     312          18 :   return 0;
     313             : }

Generated by: LCOV version 1.11