updated makefiles
[gnutls.git] / lib / x509_b64.c
blob6cb10c645cc4ce77503762111b104698ac241754
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;
199 /* decodes data and puts the result into result (locally allocated)
200 * The result_size is the return value
202 static int
203 _gnutls_base64_decode (const uint8_t * data, size_t data_size,
204 uint8_t ** result)
206 unsigned int i;
207 int pos, tmp, est;
208 uint8_t tmpres[48];
209 size_t tmpres_size, decode_size;
211 est = ((data_size * 3) / 4) + 1;
212 (*result) = gnutls_malloc (est);
213 if ((*result) == NULL)
214 return GNUTLS_E_MEMORY_ERROR;
216 pos = 0;
217 for (i = 0; i < data_size; i += 64)
219 if (data_size - i < 64)
220 decode_size = data_size - i;
221 else
222 decode_size = 64;
224 tmpres_size = sizeof(tmpres);
225 tmp = base64_decode ((void*)&data[i], decode_size, (void*)tmpres, &tmpres_size);
226 if (tmp == 0)
228 gnutls_free (*result);
229 *result = NULL;
230 return tmp;
232 memcpy (&(*result)[pos], tmpres, tmpres_size);
233 pos += tmpres_size;
235 return pos;
238 /* copies data to result but removes newlines and <CR>
239 * returns the size of the data copied.
241 inline static int
242 cpydata (const uint8_t * data, int data_size, uint8_t ** result)
244 int i, j;
246 (*result) = gnutls_malloc (data_size);
247 if (*result == NULL)
248 return GNUTLS_E_MEMORY_ERROR;
250 for (j = i = 0; i < data_size; i++)
252 if (data[i] == '\n' || data[i] == '\r' || data[i] == ' '
253 || data[i] == '\t')
254 continue;
255 (*result)[j] = data[i];
256 j++;
258 return j;
261 /* Searches the given string for ONE PEM encoded certificate, and
262 * stores it in the result.
264 * The result_size is the return value
266 #define ENDSTR "-----"
268 _gnutls_fbase64_decode (const char *header, const uint8_t * data,
269 size_t data_size, uint8_t ** result)
271 int ret;
272 static const char top[] = "-----BEGIN ";
273 static const char bottom[] = "-----END ";
274 uint8_t *rdata;
275 int rdata_size;
276 uint8_t *kdata;
277 int kdata_size;
278 char pem_header[128];
280 _gnutls_str_cpy (pem_header, sizeof (pem_header), top);
281 if (header != NULL)
282 _gnutls_str_cat (pem_header, sizeof (pem_header), header);
284 rdata = memmem (data, data_size, pem_header, strlen (pem_header));
286 if (rdata == NULL)
288 gnutls_assert ();
289 _gnutls_debug_log ("Could not find '%s'\n", pem_header);
290 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
293 data_size -= (unsigned long int) rdata - (unsigned long int) data;
295 if (data_size < 4 + strlen (bottom))
297 gnutls_assert ();
298 return GNUTLS_E_BASE64_DECODING_ERROR;
301 kdata = memmem (rdata + 1, data_size - 1, ENDSTR, sizeof (ENDSTR) - 1);
302 /* allow CR as well.
304 if (kdata == NULL)
306 gnutls_assert ();
307 _gnutls_debug_log ("Could not find '%s'\n", ENDSTR);
308 return GNUTLS_E_BASE64_DECODING_ERROR;
310 data_size -= strlen (ENDSTR);
311 data_size -= (unsigned long int) kdata - (unsigned long int) rdata;
313 rdata = kdata + strlen (ENDSTR);
315 /* position is now after the ---BEGIN--- headers */
317 kdata = memmem (rdata, data_size, bottom, strlen (bottom));
318 if (kdata == NULL)
320 gnutls_assert ();
321 return GNUTLS_E_BASE64_DECODING_ERROR;
324 /* position of kdata is before the ----END--- footer
326 rdata_size = (unsigned long int) kdata - (unsigned long int) rdata;
328 if (rdata_size < 4)
330 gnutls_assert ();
331 return GNUTLS_E_BASE64_DECODING_ERROR;
334 kdata_size = cpydata (rdata, rdata_size, &kdata);
336 if (kdata_size < 0)
338 gnutls_assert ();
339 return kdata_size;
342 if (kdata_size < 4)
344 gnutls_assert ();
345 gnutls_free (kdata);
346 return GNUTLS_E_BASE64_DECODING_ERROR;
349 if ((ret = _gnutls_base64_decode (kdata, kdata_size, result)) < 0)
351 gnutls_free (kdata);
352 gnutls_assert ();
353 return GNUTLS_E_BASE64_DECODING_ERROR;
355 gnutls_free (kdata);
357 return ret;
361 * gnutls_pem_base64_decode:
362 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
363 * @b64_data: contain the encoded data
364 * @result: the place where decoded data will be copied
365 * @result_size: holds the size of the result
367 * This function will decode the given encoded data. If the header
368 * given is non null this function will search for "-----BEGIN header"
369 * and decode only this part. Otherwise it will decode the first PEM
370 * packet found.
372 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
373 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
374 * not long enough, or 0 on success.
377 gnutls_pem_base64_decode (const char *header,
378 const gnutls_datum_t * b64_data,
379 unsigned char *result, size_t * result_size)
381 uint8_t *ret;
382 int size;
384 size =
385 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
386 if (size < 0)
387 return size;
389 if (result == NULL || *result_size < (unsigned) size)
391 gnutls_free (ret);
392 *result_size = size;
393 return GNUTLS_E_SHORT_MEMORY_BUFFER;
395 else
397 memcpy (result, ret, size);
398 gnutls_free (ret);
399 *result_size = size;
402 return 0;
406 * gnutls_pem_base64_decode_alloc:
407 * @header: The PEM header (eg. CERTIFICATE)
408 * @b64_data: contains the encoded data
409 * @result: the place where decoded data lie
411 * This function will decode the given encoded data. The decoded data
412 * will be allocated, and stored into result. If the header given is
413 * non null this function will search for "-----BEGIN header" and
414 * decode only this part. Otherwise it will decode the first PEM
415 * packet found.
417 * You should use gnutls_free() to free the returned data.
419 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
420 * an error code is returned.
423 gnutls_pem_base64_decode_alloc (const char *header,
424 const gnutls_datum_t * b64_data,
425 gnutls_datum_t * result)
427 uint8_t *ret;
428 int size;
430 if (result == NULL)
431 return GNUTLS_E_INVALID_REQUEST;
433 size =
434 _gnutls_fbase64_decode (header, b64_data->data, b64_data->size, &ret);
435 if (size < 0)
436 return size;
438 result->data = ret;
439 result->size = size;
440 return 0;