Bug Summary

File:lib/x509_b64.c
Location:line 189, column 11
Description:Although the value stored to 'pos' is used in the enclosing expression, the value is never actually read from 'pos'

Annotated Source Code

1/*
2 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3 *
4 * Author: Nikos Mavrogiannopoulos
5 *
6 * This file is part of GnuTLS.
7 *
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
20 *
21 */
22
23/* Functions that relate to base64 encoding and decoding.
24 */
25
26#include "gnutls_int.h"
27#include "gnutls_errors.h"
28#include <gnutls_datumgnutls_datum_t.h>
29#include <x509_b64.h>
30
31static const uint8_t b64table[] =
32 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
33
34static const uint8_t asciitable[128] = {
35 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
37 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
43 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
44 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
45 0xff, 0xf1, 0xff, 0xff, 0xff, 0x00, /* 0xf1 for '=' */
46 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
47 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
48 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
49 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
50 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
51 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
52 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
53 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
54 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
55 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
56 0xff, 0xff
57};
58
59inline static int
60encode (char *result, const uint8_t * data, int left)
61{
62
63 int data_len;
64
65 if (left > 3)
66 data_len = 3;
67 else
68 data_len = left;
69
70 switch (data_len)
71 {
72 case 3:
73 result[0] = b64table[(data[0] >> 2)];
74 result[1] =
75 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
76 (data[1] >> 4))];
77 result[2] =
78 b64table[((((data[1] & 0x0f) << 2) & 0xff) | (data[2] >> 6))];
79 result[3] = b64table[(((data[2] << 2) & 0xff) >> 2)];
80 break;
81 case 2:
82 result[0] = b64table[(data[0] >> 2)];
83 result[1] =
84 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
85 (data[1] >> 4))];
86 result[2] = b64table[(((data[1] << 4) & 0xff) >> 2)];
87 result[3] = '=';
88 break;
89 case 1:
90 result[0] = b64table[(data[0] >> 2)];
91 result[1] = b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff))];
92 result[2] = '=';
93 result[3] = '=';
94 break;
95 default:
96 return -1;
97 }
98
99 return 4;
100
101}
102
103/* data must be 4 bytes
104 * result should be 3 bytes
105 */
106#define TOASCII(c)(c < 127 ? asciitable[c] : 0xff) (c < 127 ? asciitable[c] : 0xff)
107inline static int
108decode (uint8_t * result, const opaque * data)
109{
110 uint8_t a1, a2;
111 int ret = 3;
112
113 a1 = TOASCII (data[0])(data[0] < 127 ? asciitable[data[0]] : 0xff);
114 a2 = TOASCII (data[1])(data[1] < 127 ? asciitable[data[1]] : 0xff);
115 if (a1 == 0xff || a2 == 0xff)
116 return -1;
117 result[0] = ((a1 << 2) & 0xff) | ((a2 >> 4) & 0xff);
118
119 a1 = a2;
120 a2 = TOASCII (data[2])(data[2] < 127 ? asciitable[data[2]] : 0xff);
121 if (a2 == 0xff)
122 return -1;
123 result[1] = ((a1 << 4) & 0xff) | ((a2 >> 2) & 0xff);
124
125 a1 = a2;
126 a2 = TOASCII (data[3])(data[3] < 127 ? asciitable[data[3]] : 0xff);
127 if (a2 == 0xff)
128 return -1;
129 result[2] = ((a1 << 6) & 0xff) | (a2 & 0xff);
130
131 if (data[2] == '=')
132 ret--;
133
134 if (data[3] == '=')
135 ret--;
136 return ret;
137}
138
139#define INCR(what, size)do { what+=size; if (what > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",139); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
\
140 do { \
141 what+=size; \
142 if (what > ret) { \
143 gnutls_assert()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",143); } while(0);
; \
144 gnutls_free( (*result)); *result = NULL((void*)0); \
145 return GNUTLS_E_INTERNAL_ERROR-59; \
146 } \
147 } while(0)
148
149/* encodes data and puts the result into result (locally allocated)
150 * The result_size (including the null terminator) is the return value.
151 */
152int
153_gnutls_fbase64_encode (const char *msg, const uint8_t * data,
154 int data_size, uint8_t ** result)
155{
156 int i, ret, tmp, j;
157 char tmpres[4];
158 uint8_t *ptr;
159 uint8_t top[80];
160 uint8_t bottom[80];
161 int pos, bytes, top_len, bottom_len;
162
163 if (msg == NULL((void*)0) || strlen(msg) > 50)
164 {
165 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",165); } while(0);
;
166 return GNUTLS_E_BASE64_ENCODING_ERROR-201;
167 }
168
169 _gnutls_str_cpy (top, sizeof(top), "-----BEGIN ");
170 _gnutls_str_cat (top, sizeof(top), msg);
171 _gnutls_str_cat (top, sizeof(top), "-----");
172
173 _gnutls_str_cpy (bottom, sizeof(bottom), "\n-----END ");
174 _gnutls_str_cat (bottom, sizeof(bottom), msg);
175 _gnutls_str_cat (bottom, sizeof(bottom), "-----\n");
176
177 top_len = strlen (top);
178 bottom_len = strlen (bottom);
179
180 ret = B64FSIZE (top_len+bottom_len, data_size)(((data_size%3==0)?((data_size*4)/3):(4 +((data_size/3)*4))) +
(top_len+bottom_len) + ((data_size%3==0)?((data_size*4)/3):(
4 +((data_size/3)*4)))/64 + (((((data_size%3==0)?((data_size*
4)/3):(4 +((data_size/3)*4))) % 64) > 0) ? 1 : 0))
;
181
182 (*result) = gnutls_calloc (1, ret + 1);
183 if ((*result) == NULL((void*)0))
184 {
185 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",185); } while(0);
;
186 return GNUTLS_E_MEMORY_ERROR-25;
187 }
188
189 bytes = pos = 0;
Although the value stored to 'pos' is used in the enclosing expression, the value is never actually read from 'pos'
190 INCR (bytes, top_len)do { bytes+=top_len; if (bytes > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",190); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
;
191 pos = top_len;
192
193 memcpy (*result, top, top_len);
194
195 for (i = j = 0; i < data_size; i += 3, j += 4)
196 {
197
198 tmp = encode (tmpres, &data[i], data_size - i);
199 if (tmp == -1)
200 {
201 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",201); } while(0);
;
202 gnutls_free ((*result));
203 *result = NULL((void*)0);
204 return GNUTLS_E_BASE64_ENCODING_ERROR-201;
205 }
206
207 INCR (bytes, 4)do { bytes+=4; if (bytes > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",207); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
;
208 ptr = &(*result)[j + pos];
209
210 if ((j) % 64 == 0)
211 {
212 INCR (bytes, 1)do { bytes+=1; if (bytes > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",212); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
;
213 pos++;
214 *ptr++ = '\n';
215 }
216 *ptr++ = tmpres[0];
217
218 if ((j + 1) % 64 == 0)
219 {
220 INCR (bytes, 1)do { bytes+=1; if (bytes > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",220); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
;
221 pos++;
222 *ptr++ = '\n';
223 }
224 *ptr++ = tmpres[1];
225
226 if ((j + 2) % 64 == 0)
227 {
228 INCR (bytes, 1)do { bytes+=1; if (bytes > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",228); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
;
229 pos++;
230 *ptr++ = '\n';
231 }
232 *ptr++ = tmpres[2];
233
234 if ((j + 3) % 64 == 0)
235 {
236 INCR (bytes, 1)do { bytes+=1; if (bytes > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",236); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
;
237 pos++;
238 *ptr++ = '\n';
239 }
240 *ptr++ = tmpres[3];
241 }
242
243 INCR (bytes, bottom_len)do { bytes+=bottom_len; if (bytes > ret) { do { if (__builtin_expect
((_gnutls_log_level >= 2), 0)) _gnutls_log( 2, "ASSERT: %s:%d\n"
, "x509_b64.c",243); } while(0);; gnutls_free( (*result)); *result
= ((void*)0); return -59; } } while(0)
;
244
245 memcpy (&(*result)[bytes - bottom_len], bottom, bottom_len);
246 (*result)[bytes] = 0;
247
248 return ret + 1;
249}
250
251/**
252 * gnutls_pem_base64_encode:
253 * @msg: is a message to be put in the header
254 * @data: contain the raw data
255 * @result: the place where base64 data will be copied
256 * @result_size: holds the size of the result
257 *
258 * This function will convert the given data to printable data, using
259 * the base64 encoding. This is the encoding used in PEM messages.
260 *
261 * The output string will be null terminated, although the size will
262 * not include the terminating null.
263 *
264 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
265 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
266 * not long enough, or 0 on success.
267 **/
268int
269gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data,
270 char *result, size_t * result_size)
271{
272 opaque *ret;
273 int size;
274
275 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
276 if (size < 0)
277 return size;
278
279 if (result == NULL((void*)0) || *result_size < (unsigned) size)
280 {
281 gnutls_free (ret);
282 *result_size = size;
283 return GNUTLS_E_SHORT_MEMORY_BUFFER-51;
284 }
285 else
286 {
287 memcpy (result, ret, size);
288 gnutls_free (ret);
289 *result_size = size - 1;
290 }
291
292 return 0;
293}
294
295/**
296 * gnutls_pem_base64_encode_alloc:
297 * @msg: is a message to be put in the encoded header
298 * @data: contains the raw data
299 * @result: will hold the newly allocated encoded data
300 *
301 * This function will convert the given data to printable data, using
302 * the base64 encoding. This is the encoding used in PEM messages.
303 * This function will allocate the required memory to hold the encoded
304 * data.
305 *
306 * You should use gnutls_free() to free the returned data.
307 *
308 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
309 * an error code is returned.
310 **/
311int
312gnutls_pem_base64_encode_alloc (const char *msg,
313 const gnutls_datum_t * data,
314 gnutls_datum_t * result)
315{
316 opaque *ret;
317 int size;
318
319 if (result == NULL((void*)0))
320 return GNUTLS_E_INVALID_REQUEST-50;
321
322 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
323 if (size < 0)
324 return size;
325
326 result->data = ret;
327 result->size = size - 1;
328 return 0;
329}
330
331
332/* decodes data and puts the result into result (locally allocated)
333 * The result_size is the return value
334 */
335static int
336_gnutls_base64_decode (const uint8_t * data, size_t data_size,
337 uint8_t ** result)
338{
339 unsigned int i, j;
340 int ret, tmp, est;
341 uint8_t tmpres[3];
342
343 est = ((data_size * 3) / 4) + 1;
344 (*result) = gnutls_malloc (est);
345 if ((*result) == NULL((void*)0))
346 return GNUTLS_E_MEMORY_ERROR-25;
347
348 ret = 0;
349 for (i = j = 0; i < data_size; i += 4, j += 3)
350 {
351 tmp = decode (tmpres, &data[i]);
352 if (tmp < 0)
353 {
354 gnutls_free (*result);
355 *result = NULL((void*)0);
356 return tmp;
357 }
358 memcpy (&(*result)[j], tmpres, tmp);
359 ret += tmp;
360 }
361 return ret;
362}
363
364/* copies data to result but removes newlines and <CR>
365 * returns the size of the data copied.
366 */
367inline static int
368cpydata (const uint8_t * data, int data_size, uint8_t ** result)
369{
370 int i, j;
371
372 (*result) = gnutls_malloc (data_size);
373 if (*result == NULL((void*)0))
374 return GNUTLS_E_MEMORY_ERROR-25;
375
376 for (j = i = 0; i < data_size; i++)
377 {
378 if (data[i] == '\n' || data[i] == '\r' || data[i] == ' '
379 || data[i] == '\t')
380 continue;
381 (*result)[j] = data[i];
382 j++;
383 }
384 return j;
385}
386
387/* Searches the given string for ONE PEM encoded certificate, and
388 * stores it in the result.
389 *
390 * The result_size is the return value
391 */
392#define ENDSTR"-----" "-----"
393int
394_gnutls_fbase64_decode (const char *header, const opaque * data,
395 size_t data_size, uint8_t ** result)
396{
397 int ret;
398 static const char top[] = "-----BEGIN ";
399 static const char bottom[] = "-----END ";
400 uint8_t *rdata;
401 int rdata_size;
402 uint8_t *kdata;
403 int kdata_size;
404 char pem_header[128];
405
406 _gnutls_str_cpy (pem_header, sizeof (pem_header), top);
407 if (header != NULL((void*)0))
408 _gnutls_str_cat (pem_header, sizeof (pem_header), header);
409
410 rdata = memmemrpl_memmem (data, data_size, pem_header, strlen (pem_header));
411
412 if (rdata == NULL((void*)0))
413 {
414 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",414); } while(0);
;
415 _gnutls_debug_log ("Could not find '%s'\n", pem_header)do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "Could not find '%s'\n", pem_header); } while(0)
;
416 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR-207;
417 }
418
419 data_size -= (unsigned long int) rdata - (unsigned long int) data;
420
421 if (data_size < 4 + strlen (bottom))
422 {
423 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",423); } while(0);
;
424 return GNUTLS_E_BASE64_DECODING_ERROR-34;
425 }
426
427 kdata = memmemrpl_memmem (rdata + 1, data_size - 1, ENDSTR"-----", sizeof (ENDSTR"-----") - 1);
428 /* allow CR as well.
429 */
430 if (kdata == NULL((void*)0))
431 {
432 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",432); } while(0);
;
433 _gnutls_debug_log ("Could not find '%s'\n", ENDSTR)do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "Could not find '%s'\n", "-----"); } while(0)
;
434 return GNUTLS_E_BASE64_DECODING_ERROR-34;
435 }
436 data_size -= strlen (ENDSTR"-----");
437 data_size -= (unsigned long int) kdata - (unsigned long int) rdata;
438
439 rdata = kdata + strlen (ENDSTR"-----");
440
441 /* position is now after the ---BEGIN--- headers */
442
443 kdata = memmemrpl_memmem (rdata, data_size, bottom, strlen (bottom));
444 if (kdata == NULL((void*)0))
445 {
446 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",446); } while(0);
;
447 return GNUTLS_E_BASE64_DECODING_ERROR-34;
448 }
449
450 /* position of kdata is before the ----END--- footer
451 */
452 rdata_size = (unsigned long int) kdata - (unsigned long int) rdata;
453
454 if (rdata_size < 4)
455 {
456 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",456); } while(0);
;
457 return GNUTLS_E_BASE64_DECODING_ERROR-34;
458 }
459
460 kdata_size = cpydata (rdata, rdata_size, &kdata);
461
462 if (kdata_size < 0)
463 {
464 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",464); } while(0);
;
465 return kdata_size;
466 }
467
468 if (kdata_size < 4)
469 {
470 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",470); } while(0);
;
471 gnutls_free (kdata);
472 return GNUTLS_E_BASE64_DECODING_ERROR-34;
473 }
474
475 if ((ret = _gnutls_base64_decode (kdata, kdata_size, result)) < 0)
476 {
477 gnutls_free (kdata);
478 gnutls_assert ()do { if (__builtin_expect((_gnutls_log_level >= 2), 0)) _gnutls_log
( 2, "ASSERT: %s:%d\n", "x509_b64.c",478); } while(0);
;
479 return GNUTLS_E_BASE64_DECODING_ERROR-34;
480 }
481 gnutls_free (kdata);
482
483 return ret;
484}
485
486/**
487 * gnutls_pem_base64_decode:
488 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
489 * @b64_data: contain the encoded data
490 * @result: the place where decoded data will be copied
491 * @result_size: holds the size of the result
492 *
493 * This function will decode the given encoded data. If the header
494 * given is non null this function will search for "-----BEGIN header"
495 * and decode only this part. Otherwise it will decode the first PEM
496 * packet found.
497 *
498 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
499 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
500 * not long enough, or 0 on success.
501 **/
502int
503gnutls_pem_base64_decode (const char *header,
504 const gnutls_datum_t * b64_data,
505 unsigned char *result, size_t * result_size)
506{
507 opaque *ret;
508 int size;
509
510 size =
511 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
512 if (size < 0)
513 return size;
514
515 if (result == NULL((void*)0) || *result_size < (unsigned) size)
516 {
517 gnutls_free (ret);
518 *result_size = size;
519 return GNUTLS_E_SHORT_MEMORY_BUFFER-51;
520 }
521 else
522 {
523 memcpy (result, ret, size);
524 gnutls_free (ret);
525 *result_size = size;
526 }
527
528 return 0;
529}
530
531/**
532 * gnutls_pem_base64_decode_alloc:
533 * @header: The PEM header (eg. CERTIFICATE)
534 * @b64_data: contains the encoded data
535 * @result: the place where decoded data lie
536 *
537 * This function will decode the given encoded data. The decoded data
538 * will be allocated, and stored into result. If the header given is
539 * non null this function will search for "-----BEGIN header" and
540 * decode only this part. Otherwise it will decode the first PEM
541 * packet found.
542 *
543 * You should use gnutls_free() to free the returned data.
544 *
545 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
546 * an error code is returned.
547 **/
548int
549gnutls_pem_base64_decode_alloc (const char *header,
550 const gnutls_datum_t * b64_data,
551 gnutls_datum_t * result)
552{
553 opaque *ret;
554 int size;
555
556 if (result == NULL((void*)0))
557 return GNUTLS_E_INVALID_REQUEST-50;
558
559 size =
560 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
561 if (size < 0)
562 return size;
563
564 result->data = ret;
565 result->size = size;
566 return 0;
567}