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->data); result->data = 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
, gnutls_datum_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
->data
= gnutls_malloc (max
+ 1);
78 if (result
->data
== NULL
)
81 return GNUTLS_E_MEMORY_ERROR
;
85 INCR (bytes
, top_len
, max
);
88 memcpy (result
->data
, 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
->data
[pos
];
103 memcpy(ptr
, tmpres
, size
);
110 INCR (bytes
, bottom_len
, max
);
112 memcpy (&result
->data
[bytes
- bottom_len
], bottom
, bottom_len
);
113 result
->data
[bytes
] = 0;
114 result
->size
= bytes
;
120 * gnutls_pem_base64_encode:
121 * @msg: is a message to be put in the header
122 * @data: contain the raw data
123 * @result: the place where base64 data will be copied
124 * @result_size: holds the size of the result
126 * This function will convert the given data to printable data, using
127 * the base64 encoding. This is the encoding used in PEM messages.
129 * The output string will be null terminated, although the size will
130 * not include the terminating null.
132 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
133 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
134 * not long enough, or 0 on success.
137 gnutls_pem_base64_encode (const char *msg
, const gnutls_datum_t
* data
,
138 char *result
, size_t * result_size
)
143 ret
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, &res
);
147 if (result
== NULL
|| *result_size
< (unsigned) res
.size
)
149 gnutls_free (res
.data
);
150 *result_size
= res
.size
+ 1;
151 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
155 memcpy (result
, res
.data
, res
.size
);
156 gnutls_free (res
.data
);
157 *result_size
= res
.size
;
164 * gnutls_pem_base64_encode_alloc:
165 * @msg: is a message to be put in the encoded header
166 * @data: contains the raw data
167 * @result: will hold the newly allocated encoded data
169 * This function will convert the given data to printable data, using
170 * the base64 encoding. This is the encoding used in PEM messages.
171 * This function will allocate the required memory to hold the encoded
174 * You should use gnutls_free() to free the returned data.
176 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
177 * an error code is returned.
180 gnutls_pem_base64_encode_alloc (const char *msg
,
181 const gnutls_datum_t
* data
,
182 gnutls_datum_t
* result
)
187 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
189 ret
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, result
);
191 return gnutls_assert_val(ret
);
196 /* copies data to result but removes newlines and <CR>
197 * returns the size of the data copied.
200 cpydata (const uint8_t * data
, int data_size
, gnutls_datum_t
*result
)
204 result
->data
= gnutls_malloc (data_size
);
205 if (result
->data
== NULL
)
206 return GNUTLS_E_MEMORY_ERROR
;
208 for (j
= i
= 0; i
< data_size
; i
++)
210 if (data
[i
] == '\n' || data
[i
] == '\r' || data
[i
] == ' '
213 else if (data
[i
] == '-') break;
214 result
->data
[j
] = data
[i
];
223 /* decodes data and puts the result into result (locally allocated)
224 * The result_size is the return value
227 _gnutls_base64_decode (const uint8_t * data
, size_t data_size
,
228 gnutls_datum_t
* result
)
231 int pos
, tmp
, est
, ret
;
233 size_t tmpres_size
, decode_size
;
234 gnutls_datum_t pdata
;
236 ret
= cpydata(data
, data_size
, &pdata
);
243 est
= ((data_size
* 3) / 4) + 1;
245 result
->data
= gnutls_malloc (est
);
246 if (result
->data
== NULL
)
247 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
250 for (i
= 0; i
< pdata
.size
; i
+= 64)
252 if (pdata
.size
- i
< 64)
253 decode_size
= pdata
.size
- i
;
257 tmpres_size
= sizeof(tmpres
);
258 tmp
= base64_decode ((void*)&pdata
.data
[i
], decode_size
, (void*)tmpres
, &tmpres_size
);
262 gnutls_free (result
->data
);
264 ret
= GNUTLS_E_PARSING_ERROR
;
267 memcpy (&result
->data
[pos
], tmpres
, tmpres_size
);
276 gnutls_free (pdata
.data
);
281 /* Searches the given string for ONE PEM encoded certificate, and
282 * stores it in the result.
284 * The result_size is the return value
286 #define ENDSTR "-----"
288 _gnutls_fbase64_decode (const char *header
, const uint8_t * data
,
289 size_t data_size
, gnutls_datum_t
* result
)
292 static const char top
[] = "-----BEGIN ";
293 static const char bottom
[] = "-----END ";
294 uint8_t *rdata
, *kdata
;
296 char pem_header
[128];
298 _gnutls_str_cpy (pem_header
, sizeof (pem_header
), top
);
300 _gnutls_str_cat (pem_header
, sizeof (pem_header
), header
);
302 rdata
= memmem (data
, data_size
, pem_header
, strlen (pem_header
));
307 _gnutls_debug_log ("Could not find '%s'\n", pem_header
);
308 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR
;
311 data_size
-= (unsigned long int) rdata
- (unsigned long int) data
;
313 if (data_size
< 4 + strlen (bottom
))
316 return GNUTLS_E_BASE64_DECODING_ERROR
;
319 kdata
= memmem (rdata
+ 1, data_size
- 1, ENDSTR
, sizeof (ENDSTR
) - 1);
325 _gnutls_debug_log ("Could not find '%s'\n", ENDSTR
);
326 return GNUTLS_E_BASE64_DECODING_ERROR
;
328 data_size
-= strlen (ENDSTR
);
329 data_size
-= (unsigned long int) kdata
- (unsigned long int) rdata
;
331 rdata
= kdata
+ strlen (ENDSTR
);
333 /* position is now after the ---BEGIN--- headers */
335 kdata
= memmem (rdata
, data_size
, bottom
, strlen (bottom
));
339 return GNUTLS_E_BASE64_DECODING_ERROR
;
342 /* position of kdata is before the ----END--- footer
344 rdata_size
= (unsigned long int) kdata
- (unsigned long int) rdata
;
349 return GNUTLS_E_BASE64_DECODING_ERROR
;
352 if ((ret
= _gnutls_base64_decode (rdata
, rdata_size
, result
)) < 0)
355 return GNUTLS_E_BASE64_DECODING_ERROR
;
362 * gnutls_pem_base64_decode:
363 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
364 * @b64_data: contain the encoded data
365 * @result: the place where decoded data will be copied
366 * @result_size: holds the size of the result
368 * This function will decode the given encoded data. If the header
369 * given is non null this function will search for "-----BEGIN header"
370 * and decode only this part. Otherwise it will decode the first PEM
373 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
374 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
375 * not long enough, or 0 on success.
378 gnutls_pem_base64_decode (const char *header
,
379 const gnutls_datum_t
* b64_data
,
380 unsigned char *result
, size_t * result_size
)
386 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &res
);
388 return gnutls_assert_val(ret
);
390 if (result
== NULL
|| *result_size
< (unsigned) res
.size
)
392 gnutls_free (res
.data
);
393 *result_size
= res
.size
;
394 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
398 memcpy (result
, res
.data
, res
.size
);
399 gnutls_free (res
.data
);
400 *result_size
= res
.size
;
407 * gnutls_pem_base64_decode_alloc:
408 * @header: The PEM header (eg. CERTIFICATE)
409 * @b64_data: contains the encoded data
410 * @result: the place where decoded data lie
412 * This function will decode the given encoded data. The decoded data
413 * will be allocated, and stored into result. If the header given is
414 * non null this function will search for "-----BEGIN header" and
415 * decode only this part. Otherwise it will decode the first PEM
418 * You should use gnutls_free() to free the returned data.
420 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
421 * an error code is returned.
424 gnutls_pem_base64_decode_alloc (const char *header
,
425 const gnutls_datum_t
* b64_data
,
426 gnutls_datum_t
* result
)
431 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
434 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, result
);
436 return gnutls_assert_val(ret
);