2 * Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation
4 * Author: Nikos Mavroyanopoulos
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 - This function will 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 the base64
297 * encoding. This is the encoding used in PEM messages. If the provided
298 * buffer is not long enough GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
300 * The output string will be null terminated, although the size will not include
301 * the terminating null.
305 gnutls_pem_base64_encode (const char *msg
, const gnutls_datum_t
* data
,
306 char *result
, size_t * result_size
)
311 size
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, &ret
);
315 if (result
== NULL
|| *result_size
< (unsigned) size
)
319 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
323 memcpy (result
, ret
, size
);
325 *result_size
= size
- 1;
332 * gnutls_pem_base64_encode_alloc - This function will convert raw data to Base64 encoded
333 * @msg: is a message to be put in the encoded header
334 * @data: contains the raw data
335 * @result: will hold the newly allocated encoded data
337 * This function will convert the given data to printable data, using the base64
338 * encoding. This is the encoding used in PEM messages. This function will
339 * allocate the required memory to hold the encoded data.
341 * You should use gnutls_free() to free the returned data.
345 gnutls_pem_base64_encode_alloc (const char *msg
,
346 const gnutls_datum_t
* data
,
347 gnutls_datum_t
* result
)
353 return GNUTLS_E_INVALID_REQUEST
;
355 size
= _gnutls_fbase64_encode (msg
, data
->data
, data
->size
, &ret
);
360 result
->size
= size
- 1;
365 /* decodes data and puts the result into result (locally allocated)
366 * The result_size is the return value
369 _gnutls_base64_decode (const uint8_t * data
, size_t data_size
,
376 est
= ((data_size
* 3) / 4) + 1;
377 (*result
) = gnutls_malloc (est
);
378 if ((*result
) == NULL
)
379 return GNUTLS_E_MEMORY_ERROR
;
382 for (i
= j
= 0; i
< data_size
; i
+= 4, j
+= 3)
384 tmp
= decode (tmpres
, &data
[i
]);
387 gnutls_free (*result
);
391 memcpy (&(*result
)[j
], tmpres
, tmp
);
397 /* copies data to result but removes newlines and <CR>
398 * returns the size of the data copied.
401 cpydata (const uint8_t * data
, int data_size
, uint8_t ** result
)
405 (*result
) = gnutls_malloc (data_size
);
407 return GNUTLS_E_MEMORY_ERROR
;
409 for (j
= i
= 0; i
< data_size
; i
++)
411 if (data
[i
] == '\n' || data
[i
] == '\r')
413 (*result
)[j
] = data
[i
];
419 /* Searches the given string for ONE PEM encoded certificate, and
420 * stores it in the result.
422 * The result_size is the return value
424 #define ENDSTR "-----\n"
425 #define ENDSTR2 "-----\r"
427 _gnutls_fbase64_decode (const char *header
, const opaque
* data
,
428 size_t data_size
, uint8_t ** result
)
431 static const char top
[] = "-----BEGIN ";
432 static const char bottom
[] = "\n-----END ";
437 char pem_header
[128];
439 _gnutls_str_cpy (pem_header
, sizeof (pem_header
), top
);
441 _gnutls_str_cat (pem_header
, sizeof (pem_header
), header
);
443 rdata
= memmem (data
, data_size
, pem_header
, strlen (pem_header
));
448 _gnutls_debug_log ("Could not find '%s'\n", pem_header
);
449 return GNUTLS_E_BASE64_DECODING_ERROR
;
452 data_size
-= (unsigned long int) rdata
- (unsigned long int) data
;
454 if (data_size
< 4 + strlen (bottom
))
457 return GNUTLS_E_BASE64_DECODING_ERROR
;
460 kdata
= memmem (rdata
, data_size
, ENDSTR
, sizeof (ENDSTR
) - 1);
464 kdata
= memmem (rdata
, data_size
, ENDSTR2
, sizeof (ENDSTR2
) - 1);
469 _gnutls_x509_log ("Could not find '%s'\n", ENDSTR
);
470 return GNUTLS_E_BASE64_DECODING_ERROR
;
472 data_size
-= strlen (ENDSTR
);
473 data_size
-= (unsigned long int) kdata
- (unsigned long int) rdata
;
475 rdata
= kdata
+ strlen (ENDSTR
);
477 /* position is now after the ---BEGIN--- headers */
479 kdata
= memmem (rdata
, data_size
, bottom
, strlen (bottom
));
483 return GNUTLS_E_BASE64_DECODING_ERROR
;
486 /* position of kdata is before the ----END--- footer
488 rdata_size
= (unsigned long int) kdata
- (unsigned long int) rdata
;
493 return GNUTLS_E_BASE64_DECODING_ERROR
;
496 kdata_size
= cpydata (rdata
, rdata_size
, &kdata
);
508 return GNUTLS_E_BASE64_DECODING_ERROR
;
511 if ((ret
= _gnutls_base64_decode (kdata
, kdata_size
, result
)) < 0)
515 return GNUTLS_E_BASE64_DECODING_ERROR
;
523 * gnutls_pem_base64_decode - This function will decode base64 encoded data
524 * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
525 * @b64_data: contain the encoded data
526 * @result: the place where decoded data will be copied
527 * @result_size: holds the size of the result
529 * This function will decode the given encoded data. If the header given
530 * is non null this function will search for "-----BEGIN header" and decode
531 * only this part. Otherwise it will decode the first PEM packet found.
533 * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not long enough,
537 gnutls_pem_base64_decode (const char *header
,
538 const gnutls_datum_t
* b64_data
,
539 unsigned char *result
, size_t * result_size
)
545 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);
549 if (result
== NULL
|| *result_size
< (unsigned) size
)
553 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
557 memcpy (result
, ret
, size
);
566 * gnutls_pem_base64_decode_alloc - This function will decode base64 encoded data
567 * @header: The PEM header (eg. CERTIFICATE)
568 * @b64_data: contains the encoded data
569 * @result: the place where decoded data lie
571 * This function will decode the given encoded data. The decoded data
572 * will be allocated, and stored into result.
573 * If the header given is non null this function will search for
574 * "-----BEGIN header" and decode only this part. Otherwise it will decode the
575 * first PEM packet found.
577 * You should use gnutls_free() to free the returned data.
581 gnutls_pem_base64_decode_alloc (const char *header
,
582 const gnutls_datum_t
* b64_data
,
583 gnutls_datum_t
* result
)
589 return GNUTLS_E_INVALID_REQUEST
;
592 _gnutls_fbase64_decode (header
, b64_data
->data
, b64_data
->size
, &ret
);