added memory handling section
[gnutls.git] / lib / x509_b64.c
blob380b77f795e1ad9a95b69921f487e40602c331a4
1 /*
2 * Copyright (C) 2000,2001 Nikos Mavroyanopoulos <nmav@hellug.gr>
4 * This file is part of GNUTLS.
6 * The GNUTLS library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "gnutls_int.h"
23 #include "gnutls_errors.h"
25 const static uint8 b64table[64] =
26 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27 const static uint8 asciitable[128] = {
28 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
29 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
30 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
32 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
35 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
36 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
37 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
38 0xff, 0xf1, 0xff, 0xff, 0xff, 0x00, /* 0xf1 for '=' */
39 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
40 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
41 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
42 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
43 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
45 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
46 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
47 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
48 0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
49 0xff, 0xff
52 inline static int encode(uint8 * result, const uint8 * data, int left)
55 int data_len;
57 if (left > 3)
58 data_len = 3;
59 else
60 data_len = left;
62 switch (data_len) {
63 case 3:
64 result[0] = b64table[(data[0] >> 2)];
65 result[1] =
66 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
67 (data[1] >> 4))];
68 result[2] =
69 b64table[((((data[1] & 0x0f) << 2) & 0xff) |
70 (data[2] >> 6))];
71 result[3] = b64table[(((data[2] << 2) & 0xff) >> 2)];
72 break;
73 case 2:
74 result[0] = b64table[(data[0] >> 2)];
75 result[1] =
76 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
77 (data[1] >> 4))];
78 result[2] = b64table[(((data[1] << 4) & 0xff) >> 2)];
79 result[3] = '=';
80 break;
81 case 1:
82 result[0] = b64table[(data[0] >> 2)];
83 result[1] =
84 b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff))];
85 result[2] = '=';
86 result[3] = '=';
87 break;
88 default:
89 return -1;
92 return 4;
96 /* data must be 4 bytes
97 * result should be 3 bytes
99 #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
100 inline static int decode(uint8 * result, const uint8 * data)
102 uint8 a1, a2;
103 int ret = 3;
105 a1 = TOASCII(data[0]);
106 a2 = TOASCII(data[1]);
107 if (a1 == 0xff || a2 == 0xff)
108 return -1;
109 result[0] = ((a1 << 2) & 0xff) | ((a2 >> 4) & 0xff);
111 a1 = a2;
112 a2 = TOASCII(data[2]);
113 if (a2 == 0xff)
114 return -1;
115 result[1] = ((a1 << 4) & 0xff) | ((a2 >> 2) & 0xff);
117 a1 = a2;
118 a2 = TOASCII(data[3]);
119 if (a2 == 0xff)
120 return -1;
121 result[2] = ((a1 << 6) & 0xff) | (a2 & 0xff);
123 if (data[2] == '=')
124 ret--;
126 if (data[3] == '=')
127 ret--;
128 return ret;
131 /* encodes data and puts the result into result (localy alocated)
132 * The result_size is the return value
134 int _gnutls_base64_encode(const uint8 * data, int data_size, uint8 ** result)
136 int i, ret, tmp, j;
137 char tmpres[4];
139 ret = data_size % 3;
140 if (ret != 0)
141 ret = 4;
142 else
143 ret = 0;
145 ret += (data_size / 3) * 4;
147 (*result) = gnutls_malloc(ret + 1);
148 if ((*result) == NULL)
149 return -1;
151 for (i = j = 0; i < data_size; i += 3, j += 4) {
152 tmp = encode(tmpres, &data[i], data_size - i);
153 if (tmp == -1) {
154 gnutls_free( (*result));
155 return -1;
157 memcpy(&(*result)[j], tmpres, tmp);
159 (*result)[ret] = 0; /* null terminated */
161 return ret;
164 /* encodes data and puts the result into result (localy alocated)
165 * The result_size is the return value
167 int _gnutls_fbase64_encode(const char *msg, const uint8 * data, int data_size,
168 uint8 ** result)
170 int i, ret, tmp, j;
171 char tmpres[4];
172 uint8 *ptr;
173 uint8 top[80];
174 uint8 bottom[80];
175 int pos;
177 memset(bottom, 0, sizeof(bottom));
178 memset(top, 0, sizeof(top));
180 if (strlen(msg) > 50)
181 return -1;
183 strcat(top, "-----BEGIN "); /* Flawfinder: ignore */
184 strcat(top, msg); /* Flawfinder: ignore */
185 strcat(top, "-----"); /* Flawfinder: ignore */
187 strcat(bottom, "\n-----END "); /* Flawfinder: ignore */
188 strcat(bottom, msg); /* Flawfinder: ignore */
189 strcat(bottom, "-----\n"); /* Flawfinder: ignore */
191 ret = data_size % 3;
192 if (ret != 0)
193 ret = 4;
194 else
195 ret = 0;
197 ret += strlen(top) + strlen(bottom);
199 tmp = (data_size / 3) * 4;
200 ret += (tmp / 64) + (tmp % 64 > 0 ? 1 : 0); /* add new lines */
201 ret += tmp;
203 (*result) = gnutls_calloc(1, ret + 1);
204 if ((*result) == NULL)
205 return -1;
207 strcat(*result, top); /* Flawfinder: ignore */
208 pos = strlen(top);
210 for (i = j = 0; i < data_size; i += 3, j += 4) {
211 tmp = encode(tmpres, &data[i], data_size - i);
212 if (tmp == -1) {
213 gnutls_free( (*result));
214 return -1;
216 ptr = &(*result)[j + pos];
218 if ((j) % 64 == 0) {
219 pos++;
220 *ptr++ = '\n';
222 *ptr++ = tmpres[0];
224 if ((j + 1) % 64 == 0) {
225 *ptr++ = '\n';
226 pos++;
228 *ptr++ = tmpres[1];
230 if ((j + 2) % 64 == 0) {
231 pos++;
232 *ptr++ = '\n';
234 *ptr++ = tmpres[2];
236 if ((j + 3) % 64 == 0) {
237 *ptr++ = '\n';
238 pos++;
240 *ptr++ = tmpres[3];
243 strcat(*result, bottom); /* Flawfinder: ignore */
244 return ret;
248 * gnutls_b64_encode_fmt - This function will convert raw data to Base64 encoded
249 * @msg: is a message to be put in the header
250 * @data: contain the raw data
251 * @result: the place where base64 data will be copied
252 * @result_size: holds the size of the result
254 * This function will convert the given data to printable data, using the base64
255 * encoding. This is the encoding used in PEM messages. If the provided
256 * buffer is not long enough GNUTLS_E_INVALID_REQUEST is returned.
260 int gnutls_b64_encode_fmt( const char* msg, const gnutls_datum *data, char* result, int* result_size) {
261 opaque* ret;
262 int size;
264 size = _gnutls_fbase64_encode( msg, data->data, data->size, &ret);
265 if (size < 0)
266 return size;
268 if (result==NULL || *result_size < size) {
269 gnutls_free(ret);
270 *result_size = size;
271 return GNUTLS_E_INVALID_REQUEST;
272 } else {
273 memcpy( result, ret, size);
274 gnutls_free(ret);
275 *result_size = size;
278 return 0;
282 /* decodes data and puts the result into result (localy alocated)
283 * The result_size is the return value
285 int _gnutls_base64_decode(const uint8 * data, int data_size, uint8 ** result)
287 int i, ret, tmp, j;
288 uint8 tmpres[3];
290 data_size /= 4;
291 data_size *= 4;
293 ret = data_size / 4 * 3;
294 (*result) = gnutls_malloc(ret+1);
295 if ((*result) == NULL)
296 return -1;
298 for (i = j = 0; i < data_size; i += 4) {
299 tmp = decode(tmpres, &data[i]);
300 if (tmp < 0) {
301 gnutls_free( *result);
302 return tmp;
304 memcpy(&(*result)[j], tmpres, tmp);
305 if (tmp < 3)
306 ret -= (3 - tmp);
307 j += 3;
309 return ret;
312 /* copies data to result but removes newlines and <CR>
313 * returns the size of the data copied.
315 inline static int cpydata(const uint8 * data, int data_size, uint8 ** result)
317 int i, j;
319 (*result) = gnutls_malloc(data_size);
320 if (*result == NULL)
321 return -1;
323 for (j = i = 0; i < data_size; i++) {
324 if (data[i] == '\n' || data[i] == '\r')
325 continue;
326 (*result)[j] = data[i];
327 j++;
329 return j;
332 /* Searches the given string for ONE PEM encoded certificate, and
333 * stores it in the result.
335 * The result_size is the return value
337 #define ENDSTR "-----\n"
338 int _gnutls_fbase64_decode( const uint8 * data, int data_size,
339 uint8 ** result)
341 int ret;
342 char top[] = "-----BEGIN ";
343 char bottom[] = "\n-----END ";
344 uint8 *rdata;
345 int rdata_size;
346 uint8 *kdata;
347 int kdata_size;
349 rdata = strstr( data, top);
350 if (rdata==NULL) {
351 gnutls_assert();
352 return -1;
354 data_size -= (unsigned long int)rdata-(unsigned long int)data;
356 if (data_size < 4 + strlen(bottom)) {
357 gnutls_assert();
358 return -1;
361 kdata = strstr( rdata, ENDSTR);
362 if (kdata==NULL) {
363 gnutls_assert();
364 return -1;
366 data_size -= strlen(ENDSTR);
367 data_size -= (unsigned long int)kdata-(unsigned long int)rdata;
369 rdata = kdata + strlen(ENDSTR);
371 /* position is now after the ---BEGIN--- headers */
373 kdata = strstr( rdata, bottom);
374 if (kdata==NULL) {
375 gnutls_assert();
376 return -1;
378 /* position of kdata is before the ----END--- footer
380 rdata_size = (unsigned long int)kdata-(unsigned long int)rdata;
382 if (rdata_size < 4) {
383 gnutls_assert();
384 return -1;
387 kdata_size = cpydata(rdata, rdata_size, &kdata);
389 if (kdata_size < 4) {
390 gnutls_assert();
391 return -1;
394 if ((ret = _gnutls_base64_decode( kdata, kdata_size, result)) < 0) {
395 gnutls_free(kdata);
396 gnutls_assert();
397 return GNUTLS_E_PARSING_ERROR;
399 gnutls_free(kdata);
401 return ret;
405 * gnutls_b64_decode_fmt - This function will decode base64 encoded data
406 * @b64_data: contain the encoded data
407 * @result: the place where decoded data will be copied
408 * @result_size: holds the size of the result
410 * This function will decode the given encoded data.
413 int gnutls_b64_decode_fmt( const gnutls_datum *b64_data, char* result, int* result_size) {
414 opaque* ret;
415 int size;
417 size = _gnutls_fbase64_decode( b64_data->data, b64_data->size, &ret);
418 if (size < 0)
419 return size;
421 if (result==NULL || *result_size < size) {
422 gnutls_free(ret);
423 *result_size = size;
424 return GNUTLS_E_INVALID_REQUEST;
425 } else {
426 memcpy( result, ret, size);
427 gnutls_free(ret);
428 *result_size = size;
431 return 0;
435 #ifdef B64_TEST
436 int main()
438 char x[100*1024];
439 int siz;
440 uint8 *b64;
442 /* for (i = 0; i < 128; i++) {
443 if (i % 6 == 0)
444 fprintf(stdout, "\n");
445 if (strchr(b64table, i) == NULL)
446 fprintf(stdout, "0x%.2x, ", 0xff);
447 else
448 fprintf(stdout, "0x%.2x, ",
449 (int) ((int) index(b64table, i) -
450 (int) b64table));
454 return 0;*/
455 siz = fread(x, 1, sizeof(x), stdin);
457 // siz = _gnutls_fbase64_encode("CERTIFICATE", x, siz, &b64);
458 siz = _gnutls_base64_encode(x, siz, &b64);
459 // siz = _gnutls_base64_decode(x, siz, &b64);
460 // siz = _gnutls_fbase64_decode("CERTIFICATE", x, siz, &b64);
463 if (siz < 0) {
464 _gnutls_log( "ERROR %d\n", siz);
465 exit(1);
467 fwrite(b64, siz, 1, stdout);
468 return 0;
472 #endif