Line data Source code
1 : /* b64dec.c - Simple Base64 decoder.
2 : * Copyright (C) 2008, 2011 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 : #include <stdio.h>
32 : #include <stdlib.h>
33 : #include <string.h>
34 : #include <errno.h>
35 : #include <assert.h>
36 :
37 : #include "i18n.h"
38 : #include "util.h"
39 :
40 :
41 : /* The reverse base-64 list used for base-64 decoding. */
42 : static unsigned char const asctobin[128] =
43 : {
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, 0xff, 0xff, 0xff, 0xff, 0xff,
49 : 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
50 : 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
51 : 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52 : 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
53 : 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
54 : 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
55 : 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
56 : 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
57 : 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
58 : 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
59 : 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
60 : };
61 :
62 : enum decoder_states
63 : {
64 : s_init, s_idle, s_lfseen, s_begin,
65 : s_b64_0, s_b64_1, s_b64_2, s_b64_3,
66 : s_waitendtitle, s_waitend
67 : };
68 :
69 :
70 :
71 : /* Initialize the context for the base64 decoder. If TITLE is NULL a
72 : plain base64 decoding is done. If it is the empty string the
73 : decoder will skip everything until a "-----BEGIN " line has been
74 : seen, decoding ends at a "----END " line.
75 :
76 : Not yet implemented: If TITLE is either "PGP" or begins with "PGP "
77 : the PGP armor lines are skipped as well. */
78 : gpg_error_t
79 0 : b64dec_start (struct b64state *state, const char *title)
80 : {
81 0 : memset (state, 0, sizeof *state);
82 0 : if (title)
83 : {
84 0 : if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' '))
85 0 : state->lasterr = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
86 : else
87 : {
88 0 : state->title = xtrystrdup (title);
89 0 : if (!state->title)
90 0 : state->lasterr = gpg_error_from_syserror ();
91 : else
92 0 : state->idx = s_init;
93 : }
94 : }
95 : else
96 0 : state->idx = s_b64_0;
97 0 : return state->lasterr;
98 : }
99 :
100 :
101 : /* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
102 : new length of the buffer at R_NBYTES. */
103 : gpg_error_t
104 0 : b64dec_proc (struct b64state *state, void *buffer, size_t length,
105 : size_t *r_nbytes)
106 : {
107 0 : enum decoder_states ds = state->idx;
108 0 : unsigned char val = state->radbuf[0];
109 0 : int pos = state->quad_count;
110 : char *d, *s;
111 :
112 0 : if (state->lasterr)
113 0 : return state->lasterr;
114 :
115 0 : if (state->stop_seen)
116 : {
117 0 : *r_nbytes = 0;
118 0 : state->lasterr = gpg_error (GPG_ERR_EOF);
119 0 : xfree (state->title);
120 0 : state->title = NULL;
121 0 : return state->lasterr;
122 : }
123 :
124 0 : for (s=d=buffer; length && !state->stop_seen; length--, s++)
125 : {
126 0 : switch (ds)
127 : {
128 : case s_idle:
129 0 : if (*s == '\n')
130 : {
131 0 : ds = s_lfseen;
132 0 : pos = 0;
133 : }
134 0 : break;
135 : case s_init:
136 0 : ds = s_lfseen;
137 : case s_lfseen:
138 0 : if (*s != "-----BEGIN "[pos])
139 0 : ds = s_idle;
140 0 : else if (pos == 10)
141 0 : ds = s_begin;
142 : else
143 0 : pos++;
144 0 : break;
145 : case s_begin:
146 0 : if (*s == '\n')
147 0 : ds = s_b64_0;
148 0 : break;
149 : case s_b64_0:
150 : case s_b64_1:
151 : case s_b64_2:
152 : case s_b64_3:
153 : {
154 : int c;
155 :
156 0 : if (*s == '-' && state->title)
157 : {
158 : /* Not a valid Base64 character: assume end
159 : header. */
160 0 : ds = s_waitend;
161 : }
162 0 : else if (*s == '=')
163 : {
164 : /* Pad character: stop */
165 0 : if (ds == s_b64_1)
166 0 : *d++ = val;
167 0 : ds = state->title? s_waitendtitle : s_waitend;
168 : }
169 0 : else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
170 : ; /* Skip white spaces. */
171 0 : else if ( (*s & 0x80)
172 0 : || (c = asctobin[*(unsigned char *)s]) == 255)
173 : {
174 : /* Skip invalid encodings. */
175 0 : state->invalid_encoding = 1;
176 : }
177 0 : else if (ds == s_b64_0)
178 : {
179 0 : val = c << 2;
180 0 : ds = s_b64_1;
181 : }
182 0 : else if (ds == s_b64_1)
183 : {
184 0 : val |= (c>>4)&3;
185 0 : *d++ = val;
186 0 : val = (c<<4)&0xf0;
187 0 : ds = s_b64_2;
188 : }
189 0 : else if (ds == s_b64_2)
190 : {
191 0 : val |= (c>>2)&15;
192 0 : *d++ = val;
193 0 : val = (c<<6)&0xc0;
194 0 : ds = s_b64_3;
195 : }
196 : else
197 : {
198 0 : val |= c&0x3f;
199 0 : *d++ = val;
200 0 : ds = s_b64_0;
201 : }
202 : }
203 0 : break;
204 : case s_waitendtitle:
205 0 : if (*s == '-')
206 0 : ds = s_waitend;
207 0 : break;
208 : case s_waitend:
209 0 : if ( *s == '\n')
210 0 : state->stop_seen = 1;
211 0 : break;
212 : default:
213 0 : BUG();
214 : }
215 : }
216 :
217 :
218 0 : state->idx = ds;
219 0 : state->radbuf[0] = val;
220 0 : state->quad_count = pos;
221 0 : *r_nbytes = (d -(char*) buffer);
222 0 : return 0;
223 : }
224 :
225 :
226 : /* This function needs to be called before releasing the decoder
227 : state. It may return an error code in case an encoding error has
228 : been found during decoding. */
229 : gpg_error_t
230 0 : b64dec_finish (struct b64state *state)
231 : {
232 0 : if (state->lasterr)
233 0 : return state->lasterr;
234 :
235 0 : xfree (state->title);
236 0 : state->title = NULL;
237 0 : return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
238 : }
|