Fix compile error.
[gnutls.git] / lib / x509_b64.c
blob421c2617923e325285299bfe8ef0e93d8ad29e27
1 /*
2 * Copyright (C) 2000, 2001, 2003, 2004, 2005, 2008 Free Software Foundation
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library 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 2.1 of
11 * the License, or (at your option) any later version.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA
25 /* Functions that relate to base64 encoding and decoding.
28 #include "gnutls_int.h"
29 #include "gnutls_errors.h"
30 #include <gnutls_datum.h>
31 #include <x509_b64.h>
33 static const uint8_t b64table[] =
34 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36 static const uint8_t asciitable[128] = {
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, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
45 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
46 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
47 0xff, 0xf1, 0xff, 0xff, 0xff, 0x00, /* 0xf1 for '=' */
48 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
49 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
50 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
51 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
52 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
53 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
54 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
55 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
56 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
57 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
58 0xff, 0xff
61 inline static int
62 encode (char *result, const uint8_t * data, int left)
65 int data_len;
67 if (left > 3)
68 data_len = 3;
69 else
70 data_len = left;
72 switch (data_len)
74 case 3:
75 result[0] = b64table[(data[0] >> 2)];
76 result[1] =
77 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
78 (data[1] >> 4))];
79 result[2] =
80 b64table[((((data[1] & 0x0f) << 2) & 0xff) | (data[2] >> 6))];
81 result[3] = b64table[(((data[2] << 2) & 0xff) >> 2)];
82 break;
83 case 2:
84 result[0] = b64table[(data[0] >> 2)];
85 result[1] =
86 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
87 (data[1] >> 4))];
88 result[2] = b64table[(((data[1] << 4) & 0xff) >> 2)];
89 result[3] = '=';
90 break;
91 case 1:
92 result[0] = b64table[(data[0] >> 2)];
93 result[1] = b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff))];
94 result[2] = '=';
95 result[3] = '=';
96 break;
97 default:
98 return -1;
101 return 4;
105 /* data must be 4 bytes
106 * result should be 3 bytes
108 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
109 inline static int
110 decode (uint8_t * result, const opaque * data)
112 uint8_t a1, a2;
113 int ret = 3;
115 a1 = TOASCII (data[0]);
116 a2 = TOASCII (data[1]);
117 if (a1 == 0xff || a2 == 0xff)
118 return -1;
119 result[0] = ((a1 << 2) & 0xff) | ((a2 >> 4) & 0xff);
121 a1 = a2;
122 a2 = TOASCII (data[2]);
123 if (a2 == 0xff)
124 return -1;
125 result[1] = ((a1 << 4) & 0xff) | ((a2 >> 2) & 0xff);
127 a1 = a2;
128 a2 = TOASCII (data[3]);
129 if (a2 == 0xff)
130 return -1;
131 result[2] = ((a1 << 6) & 0xff) | (a2 & 0xff);
133 if (data[2] == '=')
134 ret--;
136 if (data[3] == '=')
137 ret--;
138 return ret;
141 /* encodes data and puts the result into result (locally allocated)
142 * The result_size is the return value
145 _gnutls_base64_encode (const uint8_t * data, size_t data_size,
146 uint8_t ** result)
148 unsigned int i, j;
149 int ret, tmp;
150 char tmpres[4];
152 ret = B64SIZE (data_size);
154 (*result) = gnutls_malloc (ret + 1);
155 if ((*result) == NULL)
156 return GNUTLS_E_MEMORY_ERROR;
158 for (i = j = 0; i < data_size; i += 3, j += 4)
160 tmp = encode (tmpres, &data[i], data_size - i);
161 if (tmp == -1)
163 gnutls_free ((*result));
164 return GNUTLS_E_MEMORY_ERROR;
166 memcpy (&(*result)[j], tmpres, tmp);
168 (*result)[ret] = 0; /* null terminated */
170 return ret;
173 #define INCR(what, size) \
174 do { \
175 what+=size; \
176 if (what > ret) { \
177 gnutls_assert(); \
178 gnutls_free( (*result)); *result = NULL; \
179 return GNUTLS_E_INTERNAL_ERROR; \
181 } while(0)
183 /* encodes data and puts the result into result (locally allocated)
184 * The result_size (including the null terminator) is the return value.
187 _gnutls_fbase64_encode (const char *msg, const uint8_t * data,
188 int data_size, uint8_t ** result)
190 int i, ret, tmp, j;
191 char tmpres[4];
192 uint8_t *ptr;
193 uint8_t top[80];
194 uint8_t bottom[80];
195 int pos, bytes, top_len, bottom_len;
196 size_t msglen = strlen (msg);
198 if (msglen > 50)
200 gnutls_assert ();
201 return GNUTLS_E_BASE64_ENCODING_ERROR;
204 memset (bottom, 0, sizeof (bottom));
205 memset (top, 0, sizeof (top));
207 strcat (top, "-----BEGIN "); /* Flawfinder: ignore */
208 strcat (top, msg); /* Flawfinder: ignore */
209 strcat (top, "-----"); /* Flawfinder: ignore */
211 strcat (bottom, "\n-----END "); /* Flawfinder: ignore */
212 strcat (bottom, msg); /* Flawfinder: ignore */
213 strcat (bottom, "-----\n"); /* Flawfinder: ignore */
215 top_len = strlen (top);
216 bottom_len = strlen (bottom);
218 ret = B64FSIZE (msglen, data_size);
220 (*result) = gnutls_calloc (1, ret + 1);
221 if ((*result) == NULL)
223 gnutls_assert ();
224 return GNUTLS_E_MEMORY_ERROR;
227 bytes = pos = 0;
228 INCR (bytes, top_len);
229 pos = top_len;
231 strcpy (*result, top); /* Flawfinder: ignore */
233 for (i = j = 0; i < data_size; i += 3, j += 4)
236 tmp = encode (tmpres, &data[i], data_size - i);
237 if (tmp == -1)
239 gnutls_assert ();
240 gnutls_free ((*result));
241 *result = NULL;
242 return GNUTLS_E_BASE64_ENCODING_ERROR;
245 INCR (bytes, 4);
246 ptr = &(*result)[j + pos];
248 if ((j) % 64 == 0)
250 INCR (bytes, 1);
251 pos++;
252 *ptr++ = '\n';
254 *ptr++ = tmpres[0];
256 if ((j + 1) % 64 == 0)
258 INCR (bytes, 1);
259 pos++;
260 *ptr++ = '\n';
262 *ptr++ = tmpres[1];
264 if ((j + 2) % 64 == 0)
266 INCR (bytes, 1);
267 pos++;
268 *ptr++ = '\n';
270 *ptr++ = tmpres[2];
272 if ((j + 3) % 64 == 0)
274 INCR (bytes, 1);
275 pos++;
276 *ptr++ = '\n';
278 *ptr++ = tmpres[3];
281 INCR (bytes, bottom_len);
283 memcpy (&(*result)[bytes - bottom_len], bottom, bottom_len);
284 (*result)[bytes] = 0;
286 return ret + 1;
290 * gnutls_pem_base64_encode - convert raw data to Base64 encoded
291 * @msg: is a message to be put in the header
292 * @data: contain the raw data
293 * @result: the place where base64 data will be copied
294 * @result_size: holds the size of the result
296 * This function will convert the given data to printable data, using
297 * the base64 encoding. This is the encoding used in PEM messages.
299 * The output string will be null terminated, although the size will
300 * not include the terminating null.
302 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
303 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
304 * not long enough, or 0 on success.
307 gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data,
308 char *result, size_t * result_size)
310 opaque *ret;
311 int size;
313 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
314 if (size < 0)
315 return size;
317 if (result == NULL || *result_size < (unsigned) size)
319 gnutls_free (ret);
320 *result_size = size;
321 return GNUTLS_E_SHORT_MEMORY_BUFFER;
323 else
325 memcpy (result, ret, size);
326 gnutls_free (ret);
327 *result_size = size - 1;
330 return 0;
334 * gnutls_pem_base64_encode_alloc - convert raw data to Base64 encoded
335 * @msg: is a message to be put in the encoded header
336 * @data: contains the raw data
337 * @result: will hold the newly allocated encoded data
339 * This function will convert the given data to printable data, using
340 * the base64 encoding. This is the encoding used in PEM messages.
341 * This function will allocate the required memory to hold the encoded
342 * data.
344 * You should use gnutls_free() to free the returned data.
346 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
347 * an error code is returned.
350 gnutls_pem_base64_encode_alloc (const char *msg,
351 const gnutls_datum_t * data,
352 gnutls_datum_t * result)
354 opaque *ret;
355 int size;
357 if (result == NULL)
358 return GNUTLS_E_INVALID_REQUEST;
360 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
361 if (size < 0)
362 return size;
364 result->data = ret;
365 result->size = size - 1;
366 return 0;
370 /* decodes data and puts the result into result (locally allocated)
371 * The result_size is the return value
374 _gnutls_base64_decode (const uint8_t * data, size_t data_size,
375 uint8_t ** result)
377 unsigned int i, j;
378 int ret, tmp, est;
379 uint8_t tmpres[3];
381 est = ((data_size * 3) / 4) + 1;
382 (*result) = gnutls_malloc (est);
383 if ((*result) == NULL)
384 return GNUTLS_E_MEMORY_ERROR;
386 ret = 0;
387 for (i = j = 0; i < data_size; i += 4, j += 3)
389 tmp = decode (tmpres, &data[i]);
390 if (tmp < 0)
392 gnutls_free (*result);
393 *result = NULL;
394 return tmp;
396 memcpy (&(*result)[j], tmpres, tmp);
397 ret += tmp;
399 return ret;
402 /* copies data to result but removes newlines and <CR>
403 * returns the size of the data copied.
405 inline static int
406 cpydata (const uint8_t * data, int data_size, uint8_t ** result)
408 int i, j;
410 (*result) = gnutls_malloc (data_size);
411 if (*result == NULL)
412 return GNUTLS_E_MEMORY_ERROR;
414 for (j = i = 0; i < data_size; i++)
416 if (data[i] == '\n' || data[i] == '\r')
417 continue;
418 (*result)[j] = data[i];
419 j++;
421 return j;
424 /* Searches the given string for ONE PEM encoded certificate, and
425 * stores it in the result.
427 * The result_size is the return value
429 #define ENDSTR "-----\n"
430 #define ENDSTR2 "-----\r"
432 _gnutls_fbase64_decode (const char *header, const opaque * data,
433 size_t data_size, uint8_t ** result)
435 int ret;
436 static const char top[] = "-----BEGIN ";
437 static const char bottom[] = "\n-----END ";
438 uint8_t *rdata;
439 int rdata_size;
440 uint8_t *kdata;
441 int kdata_size;
442 char pem_header[128];
444 _gnutls_str_cpy (pem_header, sizeof (pem_header), top);
445 if (header != NULL)
446 _gnutls_str_cat (pem_header, sizeof (pem_header), header);
448 rdata = memmem (data, data_size, pem_header, strlen (pem_header));
450 if (rdata == NULL)
452 gnutls_assert ();
453 _gnutls_debug_log ("Could not find '%s'\n", pem_header);
454 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
457 data_size -= (unsigned long int) rdata - (unsigned long int) data;
459 if (data_size < 4 + strlen (bottom))
461 gnutls_assert ();
462 return GNUTLS_E_BASE64_DECODING_ERROR;
465 kdata = memmem (rdata, data_size, ENDSTR, sizeof (ENDSTR) - 1);
466 /* allow CR as well.
468 if (kdata == NULL)
469 kdata = memmem (rdata, data_size, ENDSTR2, sizeof (ENDSTR2) - 1);
471 if (kdata == NULL)
473 gnutls_assert ();
474 _gnutls_x509_log ("Could not find '%s'\n", ENDSTR);
475 return GNUTLS_E_BASE64_DECODING_ERROR;
477 data_size -= strlen (ENDSTR);
478 data_size -= (unsigned long int) kdata - (unsigned long int) rdata;
480 rdata = kdata + strlen (ENDSTR);
482 /* position is now after the ---BEGIN--- headers */
484 kdata = memmem (rdata, data_size, bottom, strlen (bottom));
485 if (kdata == NULL)
487 gnutls_assert ();
488 return GNUTLS_E_BASE64_DECODING_ERROR;
491 /* position of kdata is before the ----END--- footer
493 rdata_size = (unsigned long int) kdata - (unsigned long int) rdata;
495 if (rdata_size < 4)
497 gnutls_assert ();
498 return GNUTLS_E_BASE64_DECODING_ERROR;
501 kdata_size = cpydata (rdata, rdata_size, &kdata);
503 if (kdata_size < 0)
505 gnutls_assert ();
506 return kdata_size;
509 if (kdata_size < 4)
511 gnutls_assert ();
512 gnutls_free (kdata);
513 return GNUTLS_E_BASE64_DECODING_ERROR;
516 if ((ret = _gnutls_base64_decode (kdata, kdata_size, result)) < 0)
518 gnutls_free (kdata);
519 gnutls_assert ();
520 return GNUTLS_E_BASE64_DECODING_ERROR;
522 gnutls_free (kdata);
524 return ret;
528 * gnutls_pem_base64_decode - decode base64 encoded data
529 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
530 * @b64_data: contain the encoded data
531 * @result: the place where decoded data will be copied
532 * @result_size: holds the size of the result
534 * This function will decode the given encoded data. If the header
535 * given is non null this function will search for "-----BEGIN header"
536 * and decode only this part. Otherwise it will decode the first PEM
537 * packet found.
539 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
540 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
541 * not long enough, or 0 on success.
544 gnutls_pem_base64_decode (const char *header,
545 const gnutls_datum_t * b64_data,
546 unsigned char *result, size_t * result_size)
548 opaque *ret;
549 int size;
551 size =
552 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
553 if (size < 0)
554 return size;
556 if (result == NULL || *result_size < (unsigned) size)
558 gnutls_free (ret);
559 *result_size = size;
560 return GNUTLS_E_SHORT_MEMORY_BUFFER;
562 else
564 memcpy (result, ret, size);
565 gnutls_free (ret);
566 *result_size = size;
569 return 0;
573 * gnutls_pem_base64_decode_alloc - decode base64 encoded data
574 * @header: The PEM header (eg. CERTIFICATE)
575 * @b64_data: contains the encoded data
576 * @result: the place where decoded data lie
578 * This function will decode the given encoded data. The decoded data
579 * will be allocated, and stored into result. If the header given is
580 * non null this function will search for "-----BEGIN header" and
581 * decode only this part. Otherwise it will decode the first PEM
582 * packet found.
584 * You should use gnutls_free() to free the returned data.
586 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
587 * an error code is returned.
590 gnutls_pem_base64_decode_alloc (const char *header,
591 const gnutls_datum_t * b64_data,
592 gnutls_datum_t * result)
594 opaque *ret;
595 int size;
597 if (result == NULL)
598 return GNUTLS_E_INVALID_REQUEST;
600 size =
601 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
602 if (size < 0)
603 return size;
605 result->data = ret;
606 result->size = size;
607 return 0;