2 * Copyright (C) 2000, 2001, 2003, 2004, 2005, 2008, 2010 Free Software
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
26 /* Functions that relate to base64 encoding and decoding.
29 #include "gnutls_int.h"
30 #include "gnutls_errors.h"
31 #include <gnutls_datum.h>
34 static const uint8_t b64table[] =
35 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
37 static const uint8_t asciitable[128] = {
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, 0xff, 0xff, 0xff, 0xff, 0xff,
45 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
46 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
47 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
48 0xff, 0xf1, 0xff, 0xff, 0xff, 0x00, /* 0xf1 for '=' */
49 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
50 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
51 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
52 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
53 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
54 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
55 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
56 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
57 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
58 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
63 encode (char *result, const uint8_t * data, int left)
76 result[0] = b64table[(data[0] >> 2)];
78 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
81 b64table[((((data[1] & 0x0f) << 2) & 0xff) | (data[2] >> 6))];
82 result[3] = b64table[(((data[2] << 2) & 0xff) >> 2)];
85 result[0] = b64table[(data[0] >> 2)];
87 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
89 result[2] = b64table[(((data[1] << 4) & 0xff) >> 2)];
93 result[0] = b64table[(data[0] >> 2)];
94 result[1] = b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff))];
106 /* data must be 4 bytes
107 * result should be 3 bytes
109 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
111 decode (uint8_t * result, const opaque * data)
116 a1 = TOASCII (data[0]);
117 a2 = TOASCII (data[1]);
118 if (a1 == 0xff || a2 == 0xff)
120 result[0] = ((a1 << 2) & 0xff) | ((a2 >> 4) & 0xff);
123 a2 = TOASCII (data[2]);
126 result[1] = ((a1 << 4) & 0xff) | ((a2 >> 2) & 0xff);
129 a2 = TOASCII (data[3]);
132 result[2] = ((a1 << 6) & 0xff) | (a2 & 0xff);
142 /* encodes data and puts the result into result (locally allocated)
143 * The result_size is the return value
146 _gnutls_base64_encode (const uint8_t * data, size_t data_size,
153 ret = B64SIZE (data_size);
155 (*result) = gnutls_malloc (ret + 1);
156 if ((*result) == NULL)
157 return GNUTLS_E_MEMORY_ERROR;
159 for (i = j = 0; i < data_size; i += 3, j += 4)
161 tmp = encode (tmpres, &data[i], data_size - i);
164 gnutls_free ((*result));
165 return GNUTLS_E_MEMORY_ERROR;
167 memcpy (&(*result)[j], tmpres, tmp);
169 (*result)[ret] = 0; /* null terminated */
174 #define INCR(what, size) \
179 gnutls_free( (*result)); *result = NULL; \
180 return GNUTLS_E_INTERNAL_ERROR; \
184 /* encodes data and puts the result into result (locally allocated)
185 * The result_size (including the null terminator) is the return value.
188 _gnutls_fbase64_encode (const char *msg, const uint8_t * data,
189 int data_size, uint8_t ** result)
196 int pos, bytes, top_len, bottom_len;
197 size_t msglen = strlen (msg);
202 return GNUTLS_E_BASE64_ENCODING_ERROR;
205 memset (bottom, 0, sizeof (bottom));
206 memset (top, 0, sizeof (top));
208 strcat (top, "-----BEGIN "); /* Flawfinder: ignore */
209 strcat (top, msg); /* Flawfinder: ignore */
210 strcat (top, "-----"); /* Flawfinder: ignore */
212 strcat (bottom, "\n-----END "); /* Flawfinder: ignore */
213 strcat (bottom, msg); /* Flawfinder: ignore */
214 strcat (bottom, "-----\n"); /* Flawfinder: ignore */
216 top_len = strlen (top);
217 bottom_len = strlen (bottom);
219 ret = B64FSIZE (msglen, data_size);
221 (*result) = gnutls_calloc (1, ret + 1);
222 if ((*result) == NULL)
225 return GNUTLS_E_MEMORY_ERROR;
229 INCR (bytes, top_len);
232 strcpy (*result, top); /* Flawfinder: ignore */
234 for (i = j = 0; i < data_size; i += 3, j += 4)
237 tmp = encode (tmpres, &data[i], data_size - i);
241 gnutls_free ((*result));
243 return GNUTLS_E_BASE64_ENCODING_ERROR;
247 ptr = &(*result)[j + pos];
257 if ((j + 1) % 64 == 0)
265 if ((j + 2) % 64 == 0)
273 if ((j + 3) % 64 == 0)
282 INCR (bytes, bottom_len);
284 memcpy (&(*result)[bytes - bottom_len], bottom, bottom_len);
285 (*result)[bytes] = 0;
291 * gnutls_pem_base64_encode:
292 * @msg: is a message to be put in the header
293 * @data: contain the raw data
294 * @result: the place where base64 data will be copied
295 * @result_size: holds the size of the result
297 * This function will convert the given data to printable data, using
298 * the base64 encoding. This is the encoding used in PEM messages.
300 * The output string will be null terminated, although the size will
301 * not include the terminating null.
303 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
304 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
305 * not long enough, or 0 on success.
308 gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data,
309 char *result, size_t * result_size)
314 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
318 if (result == NULL || *result_size < (unsigned) size)
322 return GNUTLS_E_SHORT_MEMORY_BUFFER;
326 memcpy (result, ret, size);
328 *result_size = size - 1;
335 * gnutls_pem_base64_encode_alloc:
336 * @msg: is a message to be put in the encoded header
337 * @data: contains the raw data
338 * @result: will hold the newly allocated encoded data
340 * This function will convert the given data to printable data, using
341 * the base64 encoding. This is the encoding used in PEM messages.
342 * This function will allocate the required memory to hold the encoded
345 * You should use gnutls_free() to free the returned data.
347 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
348 * an error code is returned.
351 gnutls_pem_base64_encode_alloc (const char *msg,
352 const gnutls_datum_t * data,
353 gnutls_datum_t * result)
359 return GNUTLS_E_INVALID_REQUEST;
361 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
366 result->size = size - 1;
371 /* decodes data and puts the result into result (locally allocated)
372 * The result_size is the return value
375 _gnutls_base64_decode (const uint8_t * data, size_t data_size,
382 est = ((data_size * 3) / 4) + 1;
383 (*result) = gnutls_malloc (est);
384 if ((*result) == NULL)
385 return GNUTLS_E_MEMORY_ERROR;
388 for (i = j = 0; i < data_size; i += 4, j += 3)
390 tmp = decode (tmpres, &data[i]);
393 gnutls_free (*result);
397 memcpy (&(*result)[j], tmpres, tmp);
403 /* copies data to result but removes newlines and <CR>
404 * returns the size of the data copied.
407 cpydata (const uint8_t * data, int data_size, uint8_t ** result)
411 (*result) = gnutls_malloc (data_size);
413 return GNUTLS_E_MEMORY_ERROR;
415 for (j = i = 0; i < data_size; i++)
417 if (data[i] == '\n' || data[i] == '\r' || data[i] == ' '
420 (*result)[j] = data[i];
426 /* Searches the given string for ONE PEM encoded certificate, and
427 * stores it in the result.
429 * The result_size is the return value
431 #define ENDSTR "-----"
433 _gnutls_fbase64_decode (const char *header, const opaque * data,
434 size_t data_size, uint8_t ** result)
437 static const char top[] = "-----BEGIN ";
438 static const char bottom[] = "-----END ";
443 char pem_header[128];
445 _gnutls_str_cpy (pem_header, sizeof (pem_header), top);
447 _gnutls_str_cat (pem_header, sizeof (pem_header), header);
449 rdata = memmem (data, data_size, pem_header, strlen (pem_header));
454 _gnutls_debug_log ("Could not find '%s'\n", pem_header);
455 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
458 data_size -= (unsigned long int) rdata - (unsigned long int) data;
460 if (data_size < 4 + strlen (bottom))
463 return GNUTLS_E_BASE64_DECODING_ERROR;
466 kdata = memmem (rdata + 1, data_size - 1, ENDSTR, sizeof (ENDSTR) - 1);
472 _gnutls_x509_log ("Could not find '%s'\n", ENDSTR);
473 return GNUTLS_E_BASE64_DECODING_ERROR;
475 data_size -= strlen (ENDSTR);
476 data_size -= (unsigned long int) kdata - (unsigned long int) rdata;
478 rdata = kdata + strlen (ENDSTR);
480 /* position is now after the ---BEGIN--- headers */
482 kdata = memmem (rdata, data_size, bottom, strlen (bottom));
486 return GNUTLS_E_BASE64_DECODING_ERROR;
489 /* position of kdata is before the ----END--- footer
491 rdata_size = (unsigned long int) kdata - (unsigned long int) rdata;
496 return GNUTLS_E_BASE64_DECODING_ERROR;
499 kdata_size = cpydata (rdata, rdata_size, &kdata);
511 return GNUTLS_E_BASE64_DECODING_ERROR;
514 if ((ret = _gnutls_base64_decode (kdata, kdata_size, result)) < 0)
518 return GNUTLS_E_BASE64_DECODING_ERROR;
526 * gnutls_pem_base64_decode:
527 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
528 * @b64_data: contain the encoded data
529 * @result: the place where decoded data will be copied
530 * @result_size: holds the size of the result
532 * This function will decode the given encoded data. If the header
533 * given is non null this function will search for "-----BEGIN header"
534 * and decode only this part. Otherwise it will decode the first PEM
537 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
538 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
539 * not long enough, or 0 on success.
542 gnutls_pem_base64_decode (const char *header,
543 const gnutls_datum_t * b64_data,
544 unsigned char *result, size_t * result_size)
550 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
554 if (result == NULL || *result_size < (unsigned) size)
558 return GNUTLS_E_SHORT_MEMORY_BUFFER;
562 memcpy (result, ret, size);
571 * gnutls_pem_base64_decode_alloc:
572 * @header: The PEM header (eg. CERTIFICATE)
573 * @b64_data: contains the encoded data
574 * @result: the place where decoded data lie
576 * This function will decode the given encoded data. The decoded data
577 * will be allocated, and stored into result. If the header given is
578 * non null this function will search for "-----BEGIN header" and
579 * decode only this part. Otherwise it will decode the first PEM
582 * You should use gnutls_free() to free the returned data.
584 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
585 * an error code is returned.
588 gnutls_pem_base64_decode_alloc (const char *header,
589 const gnutls_datum_t * b64_data,
590 gnutls_datum_t * result)
596 return GNUTLS_E_INVALID_REQUEST;
599 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);