LCOV - code coverage report
Current view: top level - src - b64dec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 30 72 41.7 %
Date: 2017-03-02 16:37:58 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* b64dec.c - Simple Base64 decoder.
       2             :  * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * This file is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU Lesser General Public License as
       9             :  * published by the Free Software Foundation; either version 2.1 of
      10             :  * the License, or (at your option) any later version.
      11             :  *
      12             :  * This file is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public License
      18             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : #include <assert.h>
      26             : 
      27             : #include "gpgrt-int.h"
      28             : 
      29             : struct _gpgrt_b64state
      30             : {
      31             :   int idx;
      32             :   int quad_count;
      33             :   char *title;
      34             :   unsigned char radbuf[4];
      35             :   int stop_seen:1;
      36             :   int invalid_encoding:1;
      37             :   gpg_error_t lasterr;
      38             : };
      39             : 
      40             : /* The reverse base-64 list used for base-64 decoding. */
      41             : static unsigned char const asctobin[128] =
      42             :   {
      43             :     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      44             :     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      45             :     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      46             :     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      47             :     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      48             :     0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
      49             :     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
      50             :     0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      51             :     0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
      52             :     0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
      53             :     0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
      54             :     0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
      55             :     0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
      56             :     0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
      57             :     0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
      58             :     0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
      59             :   };
      60             : 
      61             : enum decoder_states
      62             :   {
      63             :     s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
      64             :     s_b64_0, s_b64_1, s_b64_2, s_b64_3,
      65             :     s_waitendtitle, s_waitend
      66             :   };
      67             : 
      68             : 
      69             : 
      70             : /* Allocate and initialize the context for the base64 decoder.  If
      71             :    TITLE is NULL a plain base64 decoding is done.  If it is the empty
      72             :    string the decoder will skip everything until a "-----BEGIN " line
      73             :    has been seen, decoding ends at a "----END " line.  */
      74             : gpgrt_b64state_t
      75           1 : _gpgrt_b64dec_start (const char *title)
      76             : {
      77             :   gpgrt_b64state_t state;
      78             :   char *t = NULL;
      79             : 
      80           1 :   if (title)
      81             :     {
      82           1 :       t = strdup (title);
      83           1 :       if (!t)
      84             :         return NULL;
      85             :     }
      86             : 
      87           1 :   state = calloc (1, sizeof (struct _gpgrt_b64state));
      88           1 :   if (!state)
      89             :     {
      90           0 :       free (t);
      91           0 :       return NULL;
      92             :     }
      93             : 
      94           1 :   if (t)
      95             :     {
      96           1 :       state->title = t;
      97           1 :       state->idx = s_init;
      98             :     }
      99             :   else
     100           0 :     state->idx = s_b64_0;
     101             : 
     102             :   return state;
     103             : }
     104             : 
     105             : 
     106             : /* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Stores the
     107             :    new length of the buffer at R_NBYTES. */
     108             : gpg_error_t
     109           1 : _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
     110             :                     size_t *r_nbytes)
     111             : {
     112           1 :   enum decoder_states ds = state->idx;
     113           1 :   unsigned char val = state->radbuf[0];
     114           1 :   int pos = state->quad_count;
     115             :   char *d, *s;
     116             : 
     117           1 :   if (state->lasterr)
     118             :     return state->lasterr;
     119             : 
     120           1 :   if (state->stop_seen)
     121             :     {
     122           0 :       *r_nbytes = 0;
     123           0 :       state->lasterr = gpg_error (GPG_ERR_EOF);
     124           0 :       free (state->title);
     125           0 :       state->title = NULL;
     126           0 :       return state->lasterr;
     127             :     }
     128             : 
     129         332 :   for (s=d=buffer; length && !state->stop_seen; length--, s++)
     130             :     {
     131             :     again:
     132         333 :       switch (ds)
     133             :         {
     134             :         case s_idle:
     135         332 :           if (*s == '\n')
     136             :             {
     137             :               ds = s_lfseen;
     138             :               pos = 0;
     139             :             }
     140             :           break;
     141             :         case s_init:
     142             :           ds = s_lfseen;
     143             :         case s_lfseen:
     144           1 :           if (*s != "-----BEGIN "[pos])
     145             :             {
     146             :               ds = s_idle;
     147             :               goto again;
     148             :             }
     149           0 :           else if (pos == 10)
     150             :             {
     151             :               pos = 0;
     152             :               ds = s_beginseen;
     153             :             }
     154             :           else
     155           0 :             pos++;
     156             :           break;
     157             :         case s_beginseen:
     158           0 :           if (*s != "PGP "[pos])
     159             :             ds = s_begin; /* Not a PGP armor.  */
     160           0 :           else if (pos == 3)
     161             :             ds = s_waitheader;
     162             :           else
     163           0 :             pos++;
     164             :           break;
     165             :         case s_waitheader:
     166           0 :           if (*s == '\n')
     167             :             ds = s_waitblank;
     168             :           break;
     169             :         case s_waitblank:
     170           0 :           if (*s == '\n')
     171             :             ds = s_b64_0; /* blank line found.  */
     172           0 :           else if (*s == ' ' || *s == '\r' || *s == '\t')
     173             :             ; /* Ignore spaces. */
     174             :           else
     175             :             {
     176             :               /* Armor header line.  Note that we don't care that our
     177             :                * FSM accepts a header prefixed with spaces.  */
     178             :               ds = s_waitheader; /* Wait for next header.  */
     179             :             }
     180             :           break;
     181             :         case s_begin:
     182           0 :           if (*s == '\n')
     183             :             ds = s_b64_0;
     184             :           break;
     185             :         case s_b64_0:
     186             :         case s_b64_1:
     187             :         case s_b64_2:
     188             :         case s_b64_3:
     189             :           {
     190             :             int c;
     191             : 
     192           0 :             if (*s == '-' && state->title)
     193             :               {
     194             :                 /* Not a valid Base64 character: assume end
     195             :                    header.  */
     196             :                 ds = s_waitend;
     197             :               }
     198           0 :             else if (*s == '=')
     199             :               {
     200             :                 /* Pad character: stop */
     201           0 :                 if (ds == s_b64_1)
     202           0 :                   *d++ = val;
     203           0 :                 ds = state->title? s_waitendtitle : s_waitend;
     204             :               }
     205           0 :             else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
     206             :               ; /* Skip white spaces. */
     207           0 :             else if ( (*s & 0x80)
     208           0 :                       || (c = asctobin[*(unsigned char *)s]) == 255)
     209             :               {
     210             :                 /* Skip invalid encodings.  */
     211           0 :                 state->invalid_encoding = 1;
     212             :               }
     213           0 :             else if (ds == s_b64_0)
     214             :               {
     215           0 :                 val = c << 2;
     216             :                 ds = s_b64_1;
     217             :               }
     218           0 :             else if (ds == s_b64_1)
     219             :               {
     220           0 :                 val |= (c>>4)&3;
     221           0 :                 *d++ = val;
     222           0 :                 val = (c<<4)&0xf0;
     223             :                 ds = s_b64_2;
     224             :               }
     225           0 :             else if (ds == s_b64_2)
     226             :               {
     227           0 :                 val |= (c>>2)&15;
     228           0 :                 *d++ = val;
     229           0 :                 val = (c<<6)&0xc0;
     230             :                 ds = s_b64_3;
     231             :               }
     232             :             else
     233             :               {
     234           0 :                 val |= c&0x3f;
     235           0 :                 *d++ = val;
     236             :                 ds = s_b64_0;
     237             :               }
     238             :           }
     239             :           break;
     240             :         case s_waitendtitle:
     241           0 :           if (*s == '-')
     242             :             ds = s_waitend;
     243             :           break;
     244             :         case s_waitend:
     245           0 :           if ( *s == '\n')
     246           0 :             state->stop_seen = 1;
     247             :           break;
     248             :         default:
     249           0 :           assert (!"invalid state");
     250             :         }
     251             :     }
     252             : 
     253             : 
     254           1 :   state->idx = ds;
     255           1 :   state->radbuf[0] = val;
     256           1 :   state->quad_count = pos;
     257           1 :   *r_nbytes = (d -(char*) buffer);
     258           1 :   return 0;
     259             : }
     260             : 
     261             : 
     262             : /* Return an error code in case an encoding error has been found
     263             :    during decoding. */
     264             : gpg_error_t
     265           1 : _gpgrt_b64dec_finish (gpgrt_b64state_t state)
     266             : {
     267             :   gpg_error_t err;
     268             : 
     269           1 :   if (state->lasterr)
     270             :     err = state->lasterr;
     271             :   else
     272             :     {
     273           1 :       free (state->title);
     274           1 :       err = state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
     275             :     }
     276           1 :   free (state);
     277             : 
     278           1 :   return err;
     279             : }

Generated by: LCOV version 1.13