Blame src/b64dec.c

Packit fc043f
/* b64dec.c - Simple Base64 decoder.
Packit fc043f
 * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
Packit fc043f
 * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
Packit fc043f
 *
Packit fc043f
 * This file is part of Libgpg-error.
Packit fc043f
 *
Packit fc043f
 * This file is free software; you can redistribute it and/or modify
Packit fc043f
 * it under the terms of the GNU Lesser General Public License as
Packit fc043f
 * published by the Free Software Foundation; either version 2.1 of
Packit fc043f
 * the License, or (at your option) any later version.
Packit fc043f
 *
Packit fc043f
 * This file is distributed in the hope that it will be useful,
Packit fc043f
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fc043f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit fc043f
 * GNU Lesser General Public License for more details.
Packit fc043f
 *
Packit fc043f
 * You should have received a copy of the GNU Lesser General Public License
Packit fc043f
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit fc043f
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit fc043f
 *
Packit fc043f
 * This file was originally a part of GnuPG.
Packit fc043f
 */
Packit fc043f
Packit fc043f
#include <config.h>
Packit fc043f
#include <stdio.h>
Packit fc043f
#include <stdlib.h>
Packit fc043f
#include <string.h>
Packit fc043f
Packit fc043f
#include "gpgrt-int.h"
Packit fc043f
Packit fc043f
Packit fc043f
/* The reverse base-64 list used for base-64 decoding. */
Packit fc043f
static unsigned char const asctobin[128] =
Packit fc043f
  {
Packit fc043f
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit fc043f
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit fc043f
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit fc043f
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit fc043f
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit fc043f
    0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
Packit fc043f
    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
Packit fc043f
    0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit fc043f
    0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
Packit fc043f
    0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
Packit fc043f
    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
Packit fc043f
    0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit fc043f
    0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
Packit fc043f
    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
Packit fc043f
    0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
Packit fc043f
    0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
Packit fc043f
  };
Packit fc043f
Packit fc043f
enum decoder_states
Packit fc043f
  {
Packit fc043f
    s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
Packit fc043f
    s_b64_0, s_b64_1, s_b64_2, s_b64_3,
Packit fc043f
    s_waitendtitle, s_waitend
Packit fc043f
  };
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
/* Allocate and initialize the context for the base64 decoder.  If
Packit fc043f
   TITLE is NULL a plain base64 decoding is done.  If it is the empty
Packit fc043f
   string the decoder will skip everything until a "-----BEGIN " line
Packit fc043f
   has been seen, decoding ends at a "----END " line.  */
Packit fc043f
gpgrt_b64state_t
Packit fc043f
_gpgrt_b64dec_start (const char *title)
Packit fc043f
{
Packit fc043f
  gpgrt_b64state_t state;
Packit fc043f
  char *t = NULL;
Packit fc043f
Packit fc043f
  if (title)
Packit fc043f
    {
Packit fc043f
      t = xtrystrdup (title);
Packit fc043f
      if (!t)
Packit fc043f
        return NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  state = xtrycalloc (1, sizeof (struct _gpgrt_b64state));
Packit fc043f
  if (!state)
Packit fc043f
    {
Packit fc043f
      xfree (t);
Packit fc043f
      return NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (t)
Packit fc043f
    {
Packit fc043f
      state->title = t;
Packit fc043f
      state->idx = s_init;
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    state->idx = s_b64_0;
Packit fc043f
Packit fc043f
  state->using_decoder = 1;
Packit fc043f
Packit fc043f
  return state;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Stores the
Packit fc043f
   new length of the buffer at R_NBYTES. */
Packit fc043f
gpg_err_code_t
Packit fc043f
_gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
Packit fc043f
                    size_t *r_nbytes)
Packit fc043f
{
Packit fc043f
  enum decoder_states ds = state->idx;
Packit fc043f
  unsigned char val = state->radbuf[0];
Packit fc043f
  int pos = state->quad_count;
Packit fc043f
  char *d, *s;
Packit fc043f
Packit fc043f
  if (state->lasterr)
Packit fc043f
    return state->lasterr;
Packit fc043f
Packit fc043f
  if (state->stop_seen)
Packit fc043f
    {
Packit fc043f
      *r_nbytes = 0;
Packit fc043f
      state->lasterr = GPG_ERR_EOF;
Packit fc043f
      xfree (state->title);
Packit fc043f
      state->title = NULL;
Packit fc043f
      return state->lasterr;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  for (s=d=buffer; length && !state->stop_seen; length--, s++)
Packit fc043f
    {
Packit fc043f
    again:
Packit fc043f
      switch (ds)
Packit fc043f
        {
Packit fc043f
        case s_idle:
Packit fc043f
          if (*s == '\n')
Packit fc043f
            {
Packit fc043f
              ds = s_lfseen;
Packit fc043f
              pos = 0;
Packit fc043f
            }
Packit fc043f
          break;
Packit fc043f
        case s_init:
Packit fc043f
          ds = s_lfseen;
Packit fc043f
          /* Fall through */
Packit fc043f
        case s_lfseen:
Packit fc043f
          if (*s != "-----BEGIN "[pos])
Packit fc043f
            {
Packit fc043f
              ds = s_idle;
Packit fc043f
              goto again;
Packit fc043f
            }
Packit fc043f
          else if (pos == 10)
Packit fc043f
            {
Packit fc043f
              pos = 0;
Packit fc043f
              ds = s_beginseen;
Packit fc043f
            }
Packit fc043f
          else
Packit fc043f
            pos++;
Packit fc043f
          break;
Packit fc043f
        case s_beginseen:
Packit fc043f
          if (*s != "PGP "[pos])
Packit fc043f
            ds = s_begin; /* Not a PGP armor.  */
Packit fc043f
          else if (pos == 3)
Packit fc043f
            ds = s_waitheader;
Packit fc043f
          else
Packit fc043f
            pos++;
Packit fc043f
          break;
Packit fc043f
        case s_waitheader:
Packit fc043f
          if (*s == '\n')
Packit fc043f
            ds = s_waitblank;
Packit fc043f
          break;
Packit fc043f
        case s_waitblank:
Packit fc043f
          if (*s == '\n')
Packit fc043f
            ds = s_b64_0; /* blank line found.  */
Packit fc043f
          else if (*s == ' ' || *s == '\r' || *s == '\t')
Packit fc043f
            ; /* Ignore spaces. */
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              /* Armor header line.  Note that we don't care that our
Packit fc043f
               * FSM accepts a header prefixed with spaces.  */
Packit fc043f
              ds = s_waitheader; /* Wait for next header.  */
Packit fc043f
            }
Packit fc043f
          break;
Packit fc043f
        case s_begin:
Packit fc043f
          if (*s == '\n')
Packit fc043f
            ds = s_b64_0;
Packit fc043f
          break;
Packit fc043f
        case s_b64_0:
Packit fc043f
        case s_b64_1:
Packit fc043f
        case s_b64_2:
Packit fc043f
        case s_b64_3:
Packit fc043f
          {
Packit fc043f
            int c;
Packit fc043f
Packit fc043f
            if (*s == '-' && state->title)
Packit fc043f
              {
Packit fc043f
                /* Not a valid Base64 character: assume end
Packit fc043f
                   header.  */
Packit fc043f
                ds = s_waitend;
Packit fc043f
              }
Packit fc043f
            else if (*s == '=')
Packit fc043f
              {
Packit fc043f
                /* Pad character: stop */
Packit fc043f
                if (ds == s_b64_1)
Packit fc043f
                  *d++ = val;
Packit fc043f
                ds = state->title? s_waitendtitle : s_waitend;
Packit fc043f
              }
Packit fc043f
            else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
Packit fc043f
              ; /* Skip white spaces. */
Packit fc043f
            else if ( (*s & 0x80)
Packit fc043f
                      || (c = asctobin[*(unsigned char *)s]) == 255)
Packit fc043f
              {
Packit fc043f
                /* Skip invalid encodings.  */
Packit fc043f
                state->invalid_encoding = 1;
Packit fc043f
              }
Packit fc043f
            else if (ds == s_b64_0)
Packit fc043f
              {
Packit fc043f
                val = c << 2;
Packit fc043f
                ds = s_b64_1;
Packit fc043f
              }
Packit fc043f
            else if (ds == s_b64_1)
Packit fc043f
              {
Packit fc043f
                val |= (c>>4)&3;
Packit fc043f
                *d++ = val;
Packit fc043f
                val = (c<<4)&0xf0;
Packit fc043f
                ds = s_b64_2;
Packit fc043f
              }
Packit fc043f
            else if (ds == s_b64_2)
Packit fc043f
              {
Packit fc043f
                val |= (c>>2)&1;;
Packit fc043f
                *d++ = val;
Packit fc043f
                val = (c<<6)&0xc0;
Packit fc043f
                ds = s_b64_3;
Packit fc043f
              }
Packit fc043f
            else
Packit fc043f
              {
Packit fc043f
                val |= c&0x3f;
Packit fc043f
                *d++ = val;
Packit fc043f
                ds = s_b64_0;
Packit fc043f
              }
Packit fc043f
          }
Packit fc043f
          break;
Packit fc043f
        case s_waitendtitle:
Packit fc043f
          if (*s == '-')
Packit fc043f
            ds = s_waitend;
Packit fc043f
          break;
Packit fc043f
        case s_waitend:
Packit fc043f
          if ( *s == '\n')
Packit fc043f
            state->stop_seen = 1;
Packit fc043f
          break;
Packit fc043f
        default:
Packit fc043f
          gpgrt_assert (!"invalid state");
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
Packit fc043f
  state->idx = ds;
Packit fc043f
  state->radbuf[0] = val;
Packit fc043f
  state->quad_count = pos;
Packit fc043f
  *r_nbytes = (d -(char*) buffer);
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Return an error code in case an encoding error has been found
Packit fc043f
   during decoding. */
Packit fc043f
gpg_err_code_t
Packit fc043f
_gpgrt_b64dec_finish (gpgrt_b64state_t state)
Packit fc043f
{
Packit fc043f
  gpg_error_t err;
Packit fc043f
Packit fc043f
  if (!state)
Packit fc043f
    return 0;  /* Already released.  */
Packit fc043f
Packit fc043f
  if (!state->using_decoder)
Packit fc043f
    err = GPG_ERR_CONFLICT;  /* State was allocated for the encoder.  */
Packit fc043f
  else if (state->lasterr)
Packit fc043f
    err = state->lasterr;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      free (state->title);
Packit fc043f
      err = state->invalid_encoding? GPG_ERR_BAD_DATA : 0;
Packit fc043f
    }
Packit fc043f
  free (state);
Packit fc043f
Packit fc043f
  return err;
Packit fc043f
}