Fix documentation for gnutls_dtls_set_mtu()
[gnutls.git] / lib / x509_b64.c
blob2b72ae89626f791cde08f35d54c56dd808e4120f
1 /*
2 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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.
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 License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* Functions that relate to base64 encoding and decoding.
26 #include "gnutls_int.h"
27 #include "gnutls_errors.h"
28 #include <gnutls_datum.h>
29 #include <x509_b64.h>
30 #include <base64.h>
32 #define INCR(what, size, max_len) \
33 do { \
34 what+=size; \
35 if (what > max_len) { \
36 gnutls_assert(); \
37 gnutls_free( (*result)); *result = NULL; \
38 return GNUTLS_E_INTERNAL_ERROR; \
39 } \
40 } while(0)
42 /* encodes data and puts the result into result (locally allocated)
43 * The result_size (including the null terminator) is the return value.
45 int
46 _gnutls_fbase64_encode (const char *msg, const uint8_t * data,
47 size_t data_size, uint8_t ** result)
49 int tmp;
50 unsigned int i;
51 char tmpres[66];
52 uint8_t *ptr;
53 char top[80];
54 char bottom[80];
55 size_t size, max, bytes;
56 int pos, top_len, bottom_len;
58 if (msg == NULL || strlen(msg) > 50)
60 gnutls_assert ();
61 return GNUTLS_E_BASE64_ENCODING_ERROR;
64 _gnutls_str_cpy (top, sizeof(top), "-----BEGIN ");
65 _gnutls_str_cat (top, sizeof(top), msg);
66 _gnutls_str_cat (top, sizeof(top), "-----\n");
68 _gnutls_str_cpy (bottom, sizeof(bottom), "-----END ");
69 _gnutls_str_cat (bottom, sizeof(bottom), msg);
70 _gnutls_str_cat (bottom, sizeof(bottom), "-----\n");
72 top_len = strlen (top);
73 bottom_len = strlen (bottom);
75 max = B64FSIZE (top_len+bottom_len, data_size);
77 (*result) = gnutls_calloc (1, max + 1);
78 if ((*result) == NULL)
80 gnutls_assert ();
81 return GNUTLS_E_MEMORY_ERROR;
84 bytes = pos = 0;
85 INCR (bytes, top_len, max);
86 pos = top_len;
88 memcpy (*result, top, top_len);
90 for (i = 0; i < data_size; i += 48)
92 if (data_size - i < 48)
93 tmp = data_size - i;
94 else
95 tmp = 48;
97 base64_encode ((void*)&data[i], tmp, tmpres, sizeof(tmpres));
98 size = strlen(tmpres);
100 INCR (bytes, size+1, max);
101 ptr = &(*result)[pos];
103 memcpy(ptr, tmpres, size);
104 ptr += size;
105 *ptr++ = '\n';
107 pos += size + 1;
110 INCR (bytes, bottom_len, max);
112 memcpy (&(*result)[bytes - bottom_len], bottom, bottom_len);
113 (*result)[bytes] = 0;
115 return max + 1;
119 * gnutls_pem_base64_encode:
120 * @msg: is a message to be put in the header
121 * @data: contain the raw data
122 * @result: the place where base64 data will be copied
123 * @result_size: holds the size of the result
125 * This function will convert the given data to printable data, using
126 * the base64 encoding. This is the encoding used in PEM messages.
128 * The output string will be null terminated, although the size will
129 * not include the terminating null.
131 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
132 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
133 * not long enough, or 0 on success.
136 gnutls_pem_base64_encode (const char *msg, const gnutls_datum_t * data,
137 char *result, size_t * result_size)
139 uint8_t *ret;
140 int size;
142 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
143 if (size < 0)
144 return size;
146 if (result == NULL || *result_size < (unsigned) size)
148 gnutls_free (ret);
149 *result_size = size;
150 return GNUTLS_E_SHORT_MEMORY_BUFFER;
152 else
154 memcpy (result, ret, size);
155 gnutls_free (ret);
156 *result_size = size - 1;
159 return 0;
163 * gnutls_pem_base64_encode_alloc:
164 * @msg: is a message to be put in the encoded header
165 * @data: contains the raw data
166 * @result: will hold the newly allocated encoded data
168 * This function will convert the given data to printable data, using
169 * the base64 encoding. This is the encoding used in PEM messages.
170 * This function will allocate the required memory to hold the encoded
171 * data.
173 * You should use gnutls_free() to free the returned data.
175 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
176 * an error code is returned.
179 gnutls_pem_base64_encode_alloc (const char *msg,
180 const gnutls_datum_t * data,
181 gnutls_datum_t * result)
183 uint8_t *ret;
184 int size;
186 if (result == NULL)
187 return GNUTLS_E_INVALID_REQUEST;
189 size = _gnutls_fbase64_encode (msg, data->data, data->size, &ret);
190 if (size < 0)
191 return size;
193 result->data = ret;
194 result->size = size - 1;
195 return 0;
198 /* copies data to result but removes newlines and <CR>
199 * returns the size of the data copied.
201 inline static int
202 cpydata (const uint8_t * data, int data_size, gnutls_datum_t *result)
204 int i, j;
206 result->data = gnutls_malloc (data_size);
207 if (result->data == NULL)
208 return GNUTLS_E_MEMORY_ERROR;
210 for (j = i = 0; i < data_size; i++)
212 if (data[i] == '\n' || data[i] == '\r' || data[i] == ' '
213 || data[i] == '\t')
214 continue;
215 else if (data[i] == '-') break;
216 result->data[j] = data[i];
217 j++;
220 result->size = j;
221 result->data[j] = 0;
222 return j;
225 /* decodes data and puts the result into result (locally allocated)
226 * The result_size is the return value
229 _gnutls_base64_decode (const uint8_t * data, size_t data_size,
230 gnutls_datum_t * result)
232 unsigned int i;
233 int pos, tmp, est, ret;
234 uint8_t tmpres[48];
235 size_t tmpres_size, decode_size;
236 gnutls_datum_t pdata;
238 ret = cpydata(data, data_size, &pdata);
239 if (ret < 0)
241 gnutls_assert();
242 return ret;
245 est = ((data_size * 3) / 4) + 1;
247 result->data = gnutls_malloc (est);
248 if (result->data == NULL)
249 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
252 pos = 0;
253 for (i = 0; i < pdata.size; i += 64)
255 if (pdata.size - i < 64)
256 decode_size = pdata.size - i;
257 else
258 decode_size = 64;
260 tmpres_size = sizeof(tmpres);
261 tmp = base64_decode ((void*)&pdata.data[i], decode_size, (void*)tmpres, &tmpres_size);
262 if (tmp == 0)
264 gnutls_assert();
265 gnutls_free (result->data);
266 result->data = NULL;
267 ret = GNUTLS_E_PARSING_ERROR;
268 goto cleanup;
270 memcpy (&(result->data)[pos], tmpres, tmpres_size);
271 pos += tmpres_size;
274 result->size = pos;
275 ret = pos;
277 cleanup:
278 gnutls_free (pdata.data);
279 return ret;
283 /* Searches the given string for ONE PEM encoded certificate, and
284 * stores it in the result.
286 * The result_size is the return value
288 #define ENDSTR "-----"
290 _gnutls_fbase64_decode (const char *header, const uint8_t * data,
291 size_t data_size, uint8_t ** result)
293 int ret;
294 static const char top[] = "-----BEGIN ";
295 static const char bottom[] = "-----END ";
296 gnutls_datum_t res;
297 uint8_t *rdata, *kdata;
298 int rdata_size;
299 char pem_header[128];
301 _gnutls_str_cpy (pem_header, sizeof (pem_header), top);
302 if (header != NULL)
303 _gnutls_str_cat (pem_header, sizeof (pem_header), header);
305 rdata = memmem (data, data_size, pem_header, strlen (pem_header));
307 if (rdata == NULL)
309 gnutls_assert ();
310 _gnutls_debug_log ("Could not find '%s'\n", pem_header);
311 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
314 data_size -= (unsigned long int) rdata - (unsigned long int) data;
316 if (data_size < 4 + strlen (bottom))
318 gnutls_assert ();
319 return GNUTLS_E_BASE64_DECODING_ERROR;
322 kdata = memmem (rdata + 1, data_size - 1, ENDSTR, sizeof (ENDSTR) - 1);
323 /* allow CR as well.
325 if (kdata == NULL)
327 gnutls_assert ();
328 _gnutls_debug_log ("Could not find '%s'\n", ENDSTR);
329 return GNUTLS_E_BASE64_DECODING_ERROR;
331 data_size -= strlen (ENDSTR);
332 data_size -= (unsigned long int) kdata - (unsigned long int) rdata;
334 rdata = kdata + strlen (ENDSTR);
336 /* position is now after the ---BEGIN--- headers */
338 kdata = memmem (rdata, data_size, bottom, strlen (bottom));
339 if (kdata == NULL)
341 gnutls_assert ();
342 return GNUTLS_E_BASE64_DECODING_ERROR;
345 /* position of kdata is before the ----END--- footer
347 rdata_size = (unsigned long int) kdata - (unsigned long int) rdata;
349 if (rdata_size < 4)
351 gnutls_assert ();
352 return GNUTLS_E_BASE64_DECODING_ERROR;
355 if ((ret = _gnutls_base64_decode (rdata, rdata_size, &res)) < 0)
357 gnutls_assert ();
358 return GNUTLS_E_BASE64_DECODING_ERROR;
360 *result = res.data;
362 return ret;
366 * gnutls_pem_base64_decode:
367 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
368 * @b64_data: contain the encoded data
369 * @result: the place where decoded data will be copied
370 * @result_size: holds the size of the result
372 * This function will decode the given encoded data. If the header
373 * given is non null this function will search for "-----BEGIN header"
374 * and decode only this part. Otherwise it will decode the first PEM
375 * packet found.
377 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
378 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
379 * not long enough, or 0 on success.
382 gnutls_pem_base64_decode (const char *header,
383 const gnutls_datum_t * b64_data,
384 unsigned char *result, size_t * result_size)
386 uint8_t *ret;
387 int size;
389 size =
390 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
391 if (size < 0)
392 return size;
394 if (result == NULL || *result_size < (unsigned) size)
396 gnutls_free (ret);
397 *result_size = size;
398 return GNUTLS_E_SHORT_MEMORY_BUFFER;
400 else
402 memcpy (result, ret, size);
403 gnutls_free (ret);
404 *result_size = size;
407 return 0;
411 * gnutls_pem_base64_decode_alloc:
412 * @header: The PEM header (eg. CERTIFICATE)
413 * @b64_data: contains the encoded data
414 * @result: the place where decoded data lie
416 * This function will decode the given encoded data. The decoded data
417 * will be allocated, and stored into result. If the header given is
418 * non null this function will search for "-----BEGIN header" and
419 * decode only this part. Otherwise it will decode the first PEM
420 * packet found.
422 * You should use gnutls_free() to free the returned data.
424 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
425 * an error code is returned.
428 gnutls_pem_base64_decode_alloc (const char *header,
429 const gnutls_datum_t * b64_data,
430 gnutls_datum_t * result)
432 uint8_t *ret;
433 int size;
435 if (result == NULL)
436 return GNUTLS_E_INVALID_REQUEST;
438 size =
439 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
440 if (size < 0)
441 return size;
443 result->data = ret;
444 result->size = size;
445 return 0;