LCOV - code coverage report
Current view: top level - common - tlv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 32 134 23.9 %
Date: 2016-11-29 15:00:56 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 <https://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 :       if (n < 2)
      63           0 :         return NULL; /* Buffer definitely too short for tag and length. */
      64           0 :       if (!*s || *s == 0xff)
      65             :         { /* Skip optional filler between TLV objects. */
      66           0 :           s++;
      67           0 :           n--;
      68           0 :           continue;
      69             :         }
      70           0 :       composite = !!(*s & 0x20);
      71           0 :       if ((*s & 0x1f) == 0x1f)
      72             :         { /* more tag bytes to follow */
      73           0 :           s++;
      74           0 :           n--;
      75           0 :           if (n < 2)
      76           0 :             return NULL; /* buffer definitely too short for tag and length. */
      77           0 :           if ((*s & 0x1f) == 0x1f)
      78           0 :             return NULL; /* We support only up to 2 bytes. */
      79           0 :           this_tag = (s[-1] << 8) | (s[0] & 0x7f);
      80             :         }
      81             :       else
      82           0 :         this_tag = s[0];
      83           0 :       len = s[1];
      84           0 :       s += 2; n -= 2;
      85           0 :       if (len < 0x80)
      86             :         ;
      87           0 :       else if (len == 0x81)
      88             :         { /* One byte length follows. */
      89           0 :           if (!n)
      90           0 :             return NULL; /* we expected 1 more bytes with the length. */
      91           0 :           len = s[0];
      92           0 :           s++; n--;
      93             :         }
      94           0 :       else if (len == 0x82)
      95             :         { /* Two byte length follows. */
      96           0 :           if (n < 2)
      97           0 :             return NULL; /* We expected 2 more bytes with the length. */
      98           0 :           len = ((size_t)s[0] << 8) | s[1];
      99           0 :           s += 2; n -= 2;
     100             :         }
     101             :       else
     102           0 :         return NULL; /* APDU limit is 65535, thus it does not make
     103             :                         sense to assume longer length fields. */
     104             : 
     105           0 :       if (composite && nestlevel < 100)
     106             :         { /* Dive into this composite DO after checking for a too deep
     107             :              nesting. */
     108             :           const unsigned char *tmp_s;
     109             :           size_t tmp_len;
     110             : 
     111           0 :           tmp_s = do_find_tlv (s, len, tag, &tmp_len, nestlevel+1);
     112           0 :           if (tmp_s)
     113             :             {
     114           0 :               *nbytes = tmp_len;
     115           0 :               return tmp_s;
     116             :             }
     117             :         }
     118             : 
     119           0 :       if (this_tag == tag)
     120             :         {
     121           0 :           *nbytes = len;
     122           0 :           return s;
     123             :         }
     124           0 :       if (len > n)
     125           0 :         return NULL; /* Buffer too short to skip to the next tag. */
     126           0 :       s += len; n -= len;
     127           0 :     }
     128             : }
     129             : 
     130             : 
     131             : /* Locate a TLV encoded data object in BUFFER of LENGTH and
     132             :    return a pointer to value as well as its length in NBYTES.  Return
     133             :    NULL if it was not found or if the object does not fit into the buffer. */
     134             : const unsigned char *
     135           0 : find_tlv (const unsigned char *buffer, size_t length,
     136             :           int tag, size_t *nbytes)
     137             : {
     138             :   const unsigned char *p;
     139             : 
     140           0 :   p = do_find_tlv (buffer, length, tag, nbytes, 0);
     141           0 :   if (p && *nbytes > (length - (p-buffer)))
     142           0 :     p = NULL; /* Object longer than buffer. */
     143           0 :   return p;
     144             : }
     145             : 
     146             : 
     147             : 
     148             : /* Locate a TLV encoded data object in BUFFER of LENGTH and
     149             :    return a pointer to value as well as its length in NBYTES.  Return
     150             :    NULL if it was not found.  Note, that the function does not check
     151             :    whether the value fits into the provided buffer. */
     152             : const unsigned char *
     153           0 : find_tlv_unchecked (const unsigned char *buffer, size_t length,
     154             :                     int tag, size_t *nbytes)
     155             : {
     156           0 :   return do_find_tlv (buffer, length, tag, nbytes, 0);
     157             : }
     158             : 
     159             : 
     160             : /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
     161             :    and the length part from the TLV triplet.  Update BUFFER and SIZE
     162             :    on success. */
     163             : gpg_error_t
     164           0 : parse_ber_header (unsigned char const **buffer, size_t *size,
     165             :                   int *r_class, int *r_tag,
     166             :                   int *r_constructed, int *r_ndef,
     167             :                   size_t *r_length, size_t *r_nhdr)
     168             : {
     169             :   int c;
     170             :   unsigned long tag;
     171           0 :   const unsigned char *buf = *buffer;
     172           0 :   size_t length = *size;
     173             : 
     174           0 :   *r_ndef = 0;
     175           0 :   *r_length = 0;
     176           0 :   *r_nhdr = 0;
     177             : 
     178             :   /* Get the tag. */
     179           0 :   if (!length)
     180           0 :     return gpg_err_make (default_errsource, GPG_ERR_EOF);
     181           0 :   c = *buf++; length--; ++*r_nhdr;
     182             : 
     183           0 :   *r_class = (c & 0xc0) >> 6;
     184           0 :   *r_constructed = !!(c & 0x20);
     185           0 :   tag = c & 0x1f;
     186             : 
     187           0 :   if (tag == 0x1f)
     188             :     {
     189           0 :       tag = 0;
     190             :       do
     191             :         {
     192           0 :           tag <<= 7;
     193           0 :           if (!length)
     194           0 :             return gpg_err_make (default_errsource, GPG_ERR_EOF);
     195           0 :           c = *buf++; length--; ++*r_nhdr;
     196           0 :           tag |= c & 0x7f;
     197             : 
     198             :         }
     199           0 :       while (c & 0x80);
     200             :     }
     201           0 :   *r_tag = tag;
     202             : 
     203             :   /* Get the length. */
     204           0 :   if (!length)
     205           0 :     return gpg_err_make (default_errsource, GPG_ERR_EOF);
     206           0 :   c = *buf++; length--; ++*r_nhdr;
     207             : 
     208           0 :   if ( !(c & 0x80) )
     209           0 :     *r_length = c;
     210           0 :   else if (c == 0x80)
     211           0 :     *r_ndef = 1;
     212           0 :   else if (c == 0xff)
     213           0 :     return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
     214             :   else
     215             :     {
     216           0 :       unsigned long len = 0;
     217           0 :       int count = c & 0x7f;
     218             : 
     219           0 :       if (count > sizeof (len) || count > sizeof (size_t))
     220           0 :         return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
     221             : 
     222           0 :       for (; count; count--)
     223             :         {
     224           0 :           len <<= 8;
     225           0 :           if (!length)
     226           0 :             return gpg_err_make (default_errsource, GPG_ERR_EOF);
     227           0 :           c = *buf++; length--; ++*r_nhdr;
     228           0 :           len |= c & 0xff;
     229             :         }
     230           0 :       *r_length = len;
     231             :     }
     232             : 
     233             :   /* Without this kludge some example certs can't be parsed. */
     234           0 :   if (*r_class == CLASS_UNIVERSAL && !*r_tag)
     235           0 :     *r_length = 0;
     236             : 
     237           0 :   *buffer = buf;
     238           0 :   *size = length;
     239           0 :   return 0;
     240             : }
     241             : 
     242             : 
     243             : /* FIXME: The following function should not go into this file but for
     244             :    now it is easier to keep it here. */
     245             : 
     246             : /* Return the next token of an canonical encoded S-expression.  BUF
     247             :    is the pointer to the S-expression and BUFLEN is a pointer to the
     248             :    length of this S-expression (used to validate the syntax).  Both
     249             :    are updated to reflect the new position.  The token itself is
     250             :    returned as a pointer into the original buffer at TOK and TOKLEN.
     251             :    If a parentheses is the next token, TOK will be set to NULL.
     252             :    TOKLEN is checked to be within the bounds.  On error an error code
     253             :    is returned and no pointer is not guaranteed to point to
     254             :    a meaningful value.  DEPTH should be initialized to 0 and will
     255             :    reflect on return the actual depth of the tree. To detect the end
     256             :    of the S-expression it is advisable to check DEPTH after a
     257             :    successful return.
     258             : 
     259             :    depth = 0;
     260             :    while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
     261             :           && depth)
     262             :      process_token (tok, toklen);
     263             :    if (err)
     264             :      handle_error ();
     265             :  */
     266             : gpg_error_t
     267          39 : parse_sexp (unsigned char const **buf, size_t *buflen,
     268             :             int *depth, unsigned char const **tok, size_t *toklen)
     269             : {
     270             :   const unsigned char *s;
     271             :   size_t n, vlen;
     272             : 
     273          39 :   s = *buf;
     274          39 :   n = *buflen;
     275          39 :   *tok = NULL;
     276          39 :   *toklen = 0;
     277          39 :   if (!n)
     278           0 :     return *depth ? gpg_err_make (default_errsource, GPG_ERR_INV_SEXP) : 0;
     279          39 :   if (*s == '(')
     280             :     {
     281          12 :       s++; n--;
     282          12 :       (*depth)++;
     283          12 :       *buf = s;
     284          12 :       *buflen = n;
     285          12 :       return 0;
     286             :     }
     287          27 :   if (*s == ')')
     288             :     {
     289           9 :       if (!*depth)
     290           0 :         return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     291           9 :       *toklen = 1;
     292           9 :       s++; n--;
     293           9 :       (*depth)--;
     294           9 :       *buf = s;
     295           9 :       *buflen = n;
     296           9 :       return 0;
     297             :     }
     298          42 :   for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--)
     299          24 :     vlen = vlen*10 + (*s - '0');
     300          18 :   if (!n || *s != ':')
     301           0 :     return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     302          18 :   s++; n--;
     303          18 :   if (vlen > n)
     304           0 :     return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
     305          18 :   *tok = s;
     306          18 :   *toklen = vlen;
     307          18 :   s += vlen;
     308          18 :   n -= vlen;
     309          18 :   *buf = s;
     310          18 :   *buflen = n;
     311          18 :   return 0;
     312             : }

Generated by: LCOV version 1.11