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;
199 /* decodes data and puts the result into result (locally allocated)
200 * The result_size is the return value
203 _gnutls_base64_decode (const uint8_t * data
, size_t data_size
,
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
;
217 for (i
= 0; i
< data_size
; i
+= 64)
219 if (data_size
- i
< 64)
220 decode_size
= data_size
- i
;
224 tmpres_size
= sizeof(tmpres
);
225 tmp
= base64_decode ((void*)&data
[i
], decode_size
, (void*)tmpres
, &tmpres_size
);
228 gnutls_free (*result
);
232 memcpy (&(*result
)[pos
], tmpres
, tmpres_size
);
238 /* copies data to result but removes newlines and <CR>
239 * returns the size of the data copied.
242 cpydata (const uint8_t * data
, int data_size
, uint8_t ** result
)
246 (*result
) = gnutls_malloc (data_size
);
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
] == ' '
255 (*result
)[j
] = data
[i
];
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
)
272 static const char top
[] = "-----BEGIN ";
273 static const char bottom
[] = "-----END ";
278 char pem_header
[128];
280 _gnutls_str_cpy (pem_header
, sizeof (pem_header
), top
);
282 _gnutls_str_cat (pem_header
, sizeof (pem_header
), header
);
284 rdata
= memmem (data
, data_size
, pem_header
, strlen (pem_header
));
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
))
298 return GNUTLS_E_BASE64_DECODING_ERROR
;
301 kdata
= memmem (rdata
+ 1, data_size
- 1, ENDSTR
, sizeof (ENDSTR
) - 1);
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
));
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
;
331 return GNUTLS_E_BASE64_DECODING_ERROR
;
334 kdata_size
= cpydata (rdata
, rdata_size
, &kdata
);
346 return GNUTLS_E_BASE64_DECODING_ERROR
;
349 if ((ret
= _gnutls_base64_decode (kdata
, kdata_size
, result
)) < 0)
353 return GNUTLS_E_BASE64_DECODING_ERROR
;
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
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
)
385 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);
389 if (result
== NULL
|| *result_size
< (unsigned) size
)
393 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
397 memcpy (result
, ret
, size
);
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
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
)
431 return GNUTLS_E_INVALID_REQUEST
;
434 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);