2 * Copyright (C) 2000, 2001, 2003, 2004, 2005, 2008 Free Software Foundation
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library 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 2.1 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
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 /* Functions that relate to base64 encoding and decoding.
28 #include "gnutls_int.h"
29 #include "gnutls_errors.h"
30 #include <gnutls_datum.h>
33 static const uint8_t b64table
[] =
34 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36 static const uint8_t asciitable
[128] = {
37 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
45 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
46 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
47 0xff, 0xf1, 0xff, 0xff, 0xff, 0x00, /* 0xf1 for '=' */
48 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
49 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
50 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
51 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
52 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
53 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
54 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
55 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
56 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
57 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
62 encode (char *result
, const uint8_t * data
, int left
)
75 result
[0] = b64table
[(data
[0] >> 2)];
77 b64table
[(((((data
[0] & 0x03) & 0xff) << 4) & 0xff) |
80 b64table
[((((data
[1] & 0x0f) << 2) & 0xff) | (data
[2] >> 6))];
81 result
[3] = b64table
[(((data
[2] << 2) & 0xff) >> 2)];
84 result
[0] = b64table
[(data
[0] >> 2)];
86 b64table
[(((((data
[0] & 0x03) & 0xff) << 4) & 0xff) |
88 result
[2] = b64table
[(((data
[1] << 4) & 0xff) >> 2)];
92 result
[0] = b64table
[(data
[0] >> 2)];
93 result
[1] = b64table
[(((((data
[0] & 0x03) & 0xff) << 4) & 0xff))];
105 /* data must be 4 bytes
106 * result should be 3 bytes
108 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
110 decode (uint8_t * result
, const opaque
* data
)
115 a1
= TOASCII (data
[0]);
116 a2
= TOASCII (data
[1]);
117 if (a1
== 0xff || a2
== 0xff)
119 result
[0] = ((a1
<< 2) & 0xff) | ((a2
>> 4) & 0xff);
122 a2
= TOASCII (data
[2]);
125 result
[1] = ((a1
<< 4) & 0xff) | ((a2
>> 2) & 0xff);
128 a2
= TOASCII (data
[3]);
131 result
[2] = ((a1
<< 6) & 0xff) | (a2
& 0xff);
141 /* encodes data and puts the result into result (locally allocated)
142 * The result_size is the return value
145 _gnutls_base64_encode (const uint8_t * data
, size_t data_size
,
152 ret
= B64SIZE (data_size
);
154 (*result
) = gnutls_malloc (ret
+ 1);
155 if ((*result
) == NULL
)
156 return GNUTLS_E_MEMORY_ERROR
;
158 for (i
= j
= 0; i
< data_size
; i
+= 3, j
+= 4)
160 tmp
= encode (tmpres
, &data
[i
], data_size
- i
);
163 gnutls_free ((*result
));
164 return GNUTLS_E_MEMORY_ERROR
;
166 memcpy (&(*result
)[j
], tmpres
, tmp
);
168 (*result
)[ret
] = 0; /* null terminated */
173 #define INCR(what, size) \
178 gnutls_free( (*result)); *result = NULL; \
179 return GNUTLS_E_INTERNAL_ERROR; \
183 /* encodes data and puts the result into result (locally allocated)
184 * The result_size (including the null terminator) is the return value.
187 _gnutls_fbase64_encode (const char *msg
, const uint8_t * data
,
188 int data_size
, uint8_t ** result
)
195 int pos
, bytes
, top_len
, bottom_len
;
196 size_t msglen
= strlen (msg
);
201 return GNUTLS_E_BASE64_ENCODING_ERROR
;
204 memset (bottom
, 0, sizeof (bottom
));
205 memset (top
, 0, sizeof (top
));
207 strcat (top
, "-----BEGIN "); /* Flawfinder: ignore */
208 strcat (top
, msg
); /* Flawfinder: ignore */
209 strcat (top
, "-----"); /* Flawfinder: ignore */
211 strcat (bottom
, "\n-----END "); /* Flawfinder: ignore */
212 strcat (bottom
, msg
); /* Flawfinder: ignore */
213 strcat (bottom
, "-----\n"); /* Flawfinder: ignore */
215 top_len
= strlen (top
);
216 bottom_len
= strlen (bottom
);
218 ret
= B64FSIZE (msglen
, data_size
);
220 (*result
) = gnutls_calloc (1, ret
+ 1);
221 if ((*result
) == NULL
)
224 return GNUTLS_E_MEMORY_ERROR
;
228 INCR (bytes
, top_len
);
231 strcpy (*result
, top
); /* Flawfinder: ignore */
233 for (i
= j
= 0; i
< data_size
; i
+= 3, j
+= 4)
236 tmp
= encode (tmpres
, &data
[i
], data_size
- i
);
240 gnutls_free ((*result
));
242 return GNUTLS_E_BASE64_ENCODING_ERROR
;
246 ptr
= &(*result
)[j
+ pos
];
256 if ((j
+ 1) % 64 == 0)
264 if ((j
+ 2) % 64 == 0)
272 if ((j
+ 3) % 64 == 0)
281 INCR (bytes
, bottom_len
);
283 memcpy (&(*result
)[bytes
- bottom_len
], bottom
, bottom_len
);
284 (*result
)[bytes
] = 0;
290 * gnutls_pem_base64_encode - convert raw data to Base64 encoded
291 * @msg: is a message to be put in the header
292 * @data: contain the raw data
293 * @result: the place where base64 data will be copied
294 * @result_size: holds the size of the result
296 * This function will convert the given data to printable data, using
297 * the base64 encoding. This is the encoding used in PEM messages.
299 * The output string will be null terminated, although the size will
300 * not include the terminating null.
302 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
303 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
304 * not long enough, or 0 on success.
307 gnutls_pem_base64_encode (const char *msg
, const gnutls_datum_t
* data
,
308 char *result
, size_t * result_size
)
313 size
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, &ret
);
317 if (result
== NULL
|| *result_size
< (unsigned) size
)
321 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
325 memcpy (result
, ret
, size
);
327 *result_size
= size
- 1;
334 * gnutls_pem_base64_encode_alloc - convert raw data to Base64 encoded
335 * @msg: is a message to be put in the encoded header
336 * @data: contains the raw data
337 * @result: will hold the newly allocated encoded data
339 * This function will convert the given data to printable data, using
340 * the base64 encoding. This is the encoding used in PEM messages.
341 * This function will allocate the required memory to hold the encoded
344 * You should use gnutls_free() to free the returned data.
346 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
347 * an error code is returned.
350 gnutls_pem_base64_encode_alloc (const char *msg
,
351 const gnutls_datum_t
* data
,
352 gnutls_datum_t
* result
)
358 return GNUTLS_E_INVALID_REQUEST
;
360 size
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, &ret
);
365 result
->size
= size
- 1;
370 /* decodes data and puts the result into result (locally allocated)
371 * The result_size is the return value
374 _gnutls_base64_decode (const uint8_t * data
, size_t data_size
,
381 est
= ((data_size
* 3) / 4) + 1;
382 (*result
) = gnutls_malloc (est
);
383 if ((*result
) == NULL
)
384 return GNUTLS_E_MEMORY_ERROR
;
387 for (i
= j
= 0; i
< data_size
; i
+= 4, j
+= 3)
389 tmp
= decode (tmpres
, &data
[i
]);
392 gnutls_free (*result
);
396 memcpy (&(*result
)[j
], tmpres
, tmp
);
402 /* copies data to result but removes newlines and <CR>
403 * returns the size of the data copied.
406 cpydata (const uint8_t * data
, int data_size
, uint8_t ** result
)
410 (*result
) = gnutls_malloc (data_size
);
412 return GNUTLS_E_MEMORY_ERROR
;
414 for (j
= i
= 0; i
< data_size
; i
++)
416 if (data
[i
] == '\n' || data
[i
] == '\r')
418 (*result
)[j
] = data
[i
];
424 /* Searches the given string for ONE PEM encoded certificate, and
425 * stores it in the result.
427 * The result_size is the return value
429 #define ENDSTR "-----\n"
430 #define ENDSTR2 "-----\r"
432 _gnutls_fbase64_decode (const char *header
, const opaque
* data
,
433 size_t data_size
, uint8_t ** result
)
436 static const char top
[] = "-----BEGIN ";
437 static const char bottom
[] = "\n-----END ";
442 char pem_header
[128];
444 _gnutls_str_cpy (pem_header
, sizeof (pem_header
), top
);
446 _gnutls_str_cat (pem_header
, sizeof (pem_header
), header
);
448 rdata
= memmem (data
, data_size
, pem_header
, strlen (pem_header
));
453 _gnutls_debug_log ("Could not find '%s'\n", pem_header
);
454 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR
;
457 data_size
-= (unsigned long int) rdata
- (unsigned long int) data
;
459 if (data_size
< 4 + strlen (bottom
))
462 return GNUTLS_E_BASE64_DECODING_ERROR
;
465 kdata
= memmem (rdata
, data_size
, ENDSTR
, sizeof (ENDSTR
) - 1);
469 kdata
= memmem (rdata
, data_size
, ENDSTR2
, sizeof (ENDSTR2
) - 1);
474 _gnutls_x509_log ("Could not find '%s'\n", ENDSTR
);
475 return GNUTLS_E_BASE64_DECODING_ERROR
;
477 data_size
-= strlen (ENDSTR
);
478 data_size
-= (unsigned long int) kdata
- (unsigned long int) rdata
;
480 rdata
= kdata
+ strlen (ENDSTR
);
482 /* position is now after the ---BEGIN--- headers */
484 kdata
= memmem (rdata
, data_size
, bottom
, strlen (bottom
));
488 return GNUTLS_E_BASE64_DECODING_ERROR
;
491 /* position of kdata is before the ----END--- footer
493 rdata_size
= (unsigned long int) kdata
- (unsigned long int) rdata
;
498 return GNUTLS_E_BASE64_DECODING_ERROR
;
501 kdata_size
= cpydata (rdata
, rdata_size
, &kdata
);
513 return GNUTLS_E_BASE64_DECODING_ERROR
;
516 if ((ret
= _gnutls_base64_decode (kdata
, kdata_size
, result
)) < 0)
520 return GNUTLS_E_BASE64_DECODING_ERROR
;
528 * gnutls_pem_base64_decode - decode base64 encoded data
529 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
530 * @b64_data: contain the encoded data
531 * @result: the place where decoded data will be copied
532 * @result_size: holds the size of the result
534 * This function will decode the given encoded data. If the header
535 * given is non null this function will search for "-----BEGIN header"
536 * and decode only this part. Otherwise it will decode the first PEM
539 * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
540 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
541 * not long enough, or 0 on success.
544 gnutls_pem_base64_decode (const char *header
,
545 const gnutls_datum_t
* b64_data
,
546 unsigned char *result
, size_t * result_size
)
552 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);
556 if (result
== NULL
|| *result_size
< (unsigned) size
)
560 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
564 memcpy (result
, ret
, size
);
573 * gnutls_pem_base64_decode_alloc - decode base64 encoded data
574 * @header: The PEM header (eg. CERTIFICATE)
575 * @b64_data: contains the encoded data
576 * @result: the place where decoded data lie
578 * This function will decode the given encoded data. The decoded data
579 * will be allocated, and stored into result. If the header given is
580 * non null this function will search for "-----BEGIN header" and
581 * decode only this part. Otherwise it will decode the first PEM
584 * You should use gnutls_free() to free the returned data.
586 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
587 * an error code is returned.
590 gnutls_pem_base64_decode_alloc (const char *header
,
591 const gnutls_datum_t
* b64_data
,
592 gnutls_datum_t
* result
)
598 return GNUTLS_E_INVALID_REQUEST
;
601 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);