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>
32 #define INCR(what, size, max_len) \
35 if (what > max_len) { \
37 gnutls_free( (*result)); *result = NULL; \
38 return GNUTLS_E_INTERNAL_ERROR; \
42 /* encodes data and puts the result into result (locally allocated)
43 * The result_size (including the null terminator) is the return value.
46 _gnutls_fbase64_encode (const char *msg
, const uint8_t * data
,
47 size_t data_size
, uint8_t ** result
)
55 size_t size
, max
, bytes
;
56 int pos
, top_len
, bottom_len
;
58 if (msg
== NULL
|| strlen(msg
) > 50)
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
)
81 return GNUTLS_E_MEMORY_ERROR
;
85 INCR (bytes
, top_len
, max
);
88 memcpy (*result
, top
, top_len
);
90 for (i
= 0; i
< data_size
; i
+= 48)
92 if (data_size
- i
< 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
);
110 INCR (bytes
, bottom_len
, max
);
112 memcpy (&(*result
)[bytes
- bottom_len
], bottom
, bottom_len
);
113 (*result
)[bytes
] = 0;
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
)
142 size
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, &ret
);
146 if (result
== NULL
|| *result_size
< (unsigned) size
)
150 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
154 memcpy (result
, ret
, size
);
156 *result_size
= size
- 1;
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
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
)
187 return GNUTLS_E_INVALID_REQUEST
;
189 size
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, &ret
);
194 result
->size
= size
- 1;
198 /* copies data to result but removes newlines and <CR>
199 * returns the size of the data copied.
202 cpydata (const uint8_t * data
, int data_size
, gnutls_datum_t
*result
)
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
] == ' '
215 else if (data
[i
] == '-') break;
216 result
->data
[j
] = data
[i
];
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
)
233 int pos
, tmp
, est
, ret
;
235 size_t tmpres_size
, decode_size
;
236 gnutls_datum_t pdata
;
238 ret
= cpydata(data
, data_size
, &pdata
);
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
);
253 for (i
= 0; i
< pdata
.size
; i
+= 64)
255 if (pdata
.size
- i
< 64)
256 decode_size
= pdata
.size
- i
;
260 tmpres_size
= sizeof(tmpres
);
261 tmp
= base64_decode ((void*)&pdata
.data
[i
], decode_size
, (void*)tmpres
, &tmpres_size
);
265 gnutls_free (result
->data
);
267 ret
= GNUTLS_E_PARSING_ERROR
;
270 memcpy (&(result
->data
)[pos
], tmpres
, tmpres_size
);
278 gnutls_free (pdata
.data
);
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
)
294 static const char top
[] = "-----BEGIN ";
295 static const char bottom
[] = "-----END ";
297 uint8_t *rdata
, *kdata
;
299 char pem_header
[128];
301 _gnutls_str_cpy (pem_header
, sizeof (pem_header
), top
);
303 _gnutls_str_cat (pem_header
, sizeof (pem_header
), header
);
305 rdata
= memmem (data
, data_size
, pem_header
, strlen (pem_header
));
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
))
319 return GNUTLS_E_BASE64_DECODING_ERROR
;
322 kdata
= memmem (rdata
+ 1, data_size
- 1, ENDSTR
, sizeof (ENDSTR
) - 1);
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
));
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
;
352 return GNUTLS_E_BASE64_DECODING_ERROR
;
355 if ((ret
= _gnutls_base64_decode (rdata
, rdata_size
, &res
)) < 0)
358 return GNUTLS_E_BASE64_DECODING_ERROR
;
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
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
)
390 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);
394 if (result
== NULL
|| *result_size
< (unsigned) size
)
398 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
402 memcpy (result
, ret
, size
);
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
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
)
436 return GNUTLS_E_INVALID_REQUEST
;
439 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);