Line data Source code
1 : /*
2 : * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3 : * Copyright (C) 2017 Red Hat, Inc.
4 : *
5 : * Author: Nikos Mavrogiannopoulos
6 : *
7 : * This file is part of GnuTLS.
8 : *
9 : * The GnuTLS is free software; you can redistribute it and/or
10 : * modify it under the terms of the GNU Lesser General Public License
11 : * as published by the Free Software Foundation; either version 2.1 of
12 : * the License, or (at your option) any later version.
13 : *
14 : * This library is distributed in the hope that it will be useful, but
15 : * WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : * Lesser General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU Lesser General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>
21 : *
22 : */
23 :
24 : /* Functions that relate to base64 encoding and decoding.
25 : */
26 :
27 : #include "gnutls_int.h"
28 : #include "errors.h"
29 : #include <datum.h>
30 : #include <x509_b64.h>
31 : #include <nettle/base64.h>
32 :
33 : #define INCR(what, size, max_len) \
34 : do { \
35 : what+=size; \
36 : if (what > max_len) { \
37 : gnutls_assert(); \
38 : gnutls_free( result->data); result->data = NULL; \
39 : return GNUTLS_E_INTERNAL_ERROR; \
40 : } \
41 : } while(0)
42 :
43 : /* encodes data and puts the result into result (locally allocated)
44 : * The result_size (including the null terminator) is the return value.
45 : */
46 : int
47 15255 : _gnutls_fbase64_encode(const char *msg, const uint8_t * data,
48 : size_t data_size, gnutls_datum_t * result)
49 : {
50 15255 : int tmp;
51 15255 : unsigned int i;
52 15255 : uint8_t tmpres[66];
53 15255 : uint8_t *ptr;
54 15255 : char top[80];
55 15255 : char bottom[80];
56 15255 : size_t size, max, bytes;
57 15255 : int pos, top_len = 0, bottom_len = 0;
58 15255 : unsigned raw_encoding = 0;
59 :
60 15255 : if (msg == NULL || msg[0] == 0)
61 : raw_encoding = 1;
62 :
63 15165 : if (!raw_encoding) {
64 15165 : if (strlen(msg) > 50) {
65 0 : gnutls_assert();
66 0 : return GNUTLS_E_BASE64_ENCODING_ERROR;
67 : }
68 :
69 15165 : _gnutls_str_cpy(top, sizeof(top), "-----BEGIN ");
70 15165 : _gnutls_str_cat(top, sizeof(top), msg);
71 15165 : _gnutls_str_cat(top, sizeof(top), "-----\n");
72 :
73 15165 : _gnutls_str_cpy(bottom, sizeof(bottom), "-----END ");
74 15165 : _gnutls_str_cat(bottom, sizeof(bottom), msg);
75 15165 : _gnutls_str_cat(bottom, sizeof(bottom), "-----\n");
76 :
77 15165 : top_len = strlen(top);
78 15165 : bottom_len = strlen(bottom);
79 : }
80 :
81 15255 : max = B64FSIZE(top_len + bottom_len, data_size);
82 :
83 15255 : result->data = gnutls_malloc(max + 1);
84 15255 : if (result->data == NULL) {
85 0 : gnutls_assert();
86 0 : return GNUTLS_E_MEMORY_ERROR;
87 : }
88 :
89 15255 : bytes = 0;
90 15255 : INCR(bytes, top_len, max);
91 15255 : pos = top_len;
92 :
93 15255 : memcpy(result->data, top, top_len);
94 :
95 77818 : for (i = 0; i < data_size; i += 48) {
96 62563 : if (data_size - i < 48)
97 15143 : tmp = data_size - i;
98 : else
99 : tmp = 48;
100 :
101 62563 : size = BASE64_ENCODE_RAW_LENGTH(tmp);
102 62563 : if (sizeof(tmpres) < size)
103 0 : return gnutls_assert_val(GNUTLS_E_BASE64_ENCODING_ERROR);
104 :
105 62563 : base64_encode_raw((void*)tmpres, tmp, &data[i]);
106 :
107 62563 : INCR(bytes, size + 1, max);
108 62563 : ptr = &result->data[pos];
109 :
110 62563 : memcpy(ptr, tmpres, size);
111 62563 : ptr += size;
112 62563 : pos += size;
113 62563 : if (!raw_encoding) {
114 61135 : *ptr++ = '\n';
115 61135 : pos++;
116 : } else {
117 : bytes--;
118 : }
119 : }
120 :
121 15255 : INCR(bytes, bottom_len, max);
122 :
123 15255 : memcpy(&result->data[bytes - bottom_len], bottom, bottom_len);
124 15255 : result->data[bytes] = 0;
125 15255 : result->size = bytes;
126 :
127 15255 : return max + 1;
128 : }
129 :
130 : /**
131 : * gnutls_pem_base64_encode:
132 : * @msg: is a message to be put in the header (may be %NULL)
133 : * @data: contain the raw data
134 : * @result: the place where base64 data will be copied
135 : * @result_size: holds the size of the result
136 : *
137 : * This function will convert the given data to printable data, using
138 : * the base64 encoding. This is the encoding used in PEM messages.
139 : *
140 : * The output string will be null terminated, although the output size will
141 : * not include the terminating null.
142 : *
143 : * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
144 : * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
145 : * not long enough, or 0 on success.
146 : **/
147 : int
148 70 : gnutls_pem_base64_encode(const char *msg, const gnutls_datum_t * data,
149 : char *result, size_t * result_size)
150 : {
151 70 : gnutls_datum_t res;
152 70 : int ret;
153 :
154 70 : ret = _gnutls_fbase64_encode(msg, data->data, data->size, &res);
155 70 : if (ret < 0)
156 : return ret;
157 :
158 70 : if (result == NULL || *result_size < (unsigned) res.size) {
159 11 : gnutls_free(res.data);
160 11 : *result_size = res.size + 1;
161 11 : return GNUTLS_E_SHORT_MEMORY_BUFFER;
162 : } else {
163 59 : memcpy(result, res.data, res.size);
164 59 : gnutls_free(res.data);
165 59 : *result_size = res.size;
166 : }
167 :
168 59 : return 0;
169 : }
170 :
171 : /**
172 : * gnutls_pem_base64_encode2:
173 : * @header: is a message to be put in the encoded header (may be %NULL)
174 : * @data: contains the raw data
175 : * @result: will hold the newly allocated encoded data
176 : *
177 : * This function will convert the given data to printable data, using
178 : * the base64 encoding. This is the encoding used in PEM messages.
179 : * This function will allocate the required memory to hold the encoded
180 : * data.
181 : *
182 : * You should use gnutls_free() to free the returned data.
183 : *
184 : * Note, that prior to GnuTLS 3.4.0 this function was available
185 : * under the name gnutls_pem_base64_encode_alloc(). There is
186 : * compatibility macro pointing to this function.
187 : *
188 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
189 : * an error code is returned.
190 : *
191 : * Since: 3.4.0
192 : **/
193 : int
194 11980 : gnutls_pem_base64_encode2(const char *header,
195 : const gnutls_datum_t * data,
196 : gnutls_datum_t * result)
197 : {
198 11980 : int ret;
199 :
200 11980 : if (result == NULL)
201 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
202 :
203 11980 : ret = _gnutls_fbase64_encode(header, data->data, data->size, result);
204 11980 : if (ret < 0)
205 0 : return gnutls_assert_val(ret);
206 :
207 : return 0;
208 : }
209 :
210 : /* copies data to result but removes newlines and <CR>
211 : * returns the size of the data copied.
212 : *
213 : * It will fail with GNUTLS_E_BASE64_DECODING_ERROR if the
214 : * end-result is the empty string.
215 : */
216 : inline static int
217 19984 : cpydata(const uint8_t * data, int data_size, gnutls_datum_t * result)
218 : {
219 19984 : int i, j;
220 :
221 19984 : result->data = gnutls_malloc(data_size + 1);
222 19984 : if (result->data == NULL)
223 : return GNUTLS_E_MEMORY_ERROR;
224 :
225 21946600 : for (j = i = 0; i < data_size; i++) {
226 21930100 : if (data[i] == '\n' || data[i] == '\r' || data[i] == ' '
227 21589800 : || data[i] == '\t')
228 340900 : continue;
229 21589200 : else if (data[i] == '-')
230 : break;
231 21585700 : result->data[j] = data[i];
232 21585700 : j++;
233 : }
234 :
235 19984 : result->size = j;
236 19984 : result->data[j] = 0;
237 :
238 19984 : if (j==0) {
239 1233 : gnutls_free(result->data);
240 1233 : return gnutls_assert_val(GNUTLS_E_BASE64_DECODING_ERROR);
241 : }
242 :
243 : return j;
244 : }
245 :
246 : /* decodes data and puts the result into result (locally allocated).
247 : * Note that encodings of zero-length strings are being rejected
248 : * with GNUTLS_E_BASE64_DECODING_ERROR.
249 : *
250 : * The result_size is the return value.
251 : */
252 : int
253 19985 : _gnutls_base64_decode(const uint8_t * data, size_t data_size,
254 : gnutls_datum_t * result)
255 : {
256 19985 : int ret;
257 19985 : size_t size;
258 19985 : gnutls_datum_t pdata;
259 19985 : struct base64_decode_ctx ctx;
260 :
261 19985 : if (data_size == 0) {
262 1 : result->data = (unsigned char*)gnutls_strdup("");
263 1 : if (result->data == NULL)
264 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
265 1 : result->size = 0;
266 1 : return 0;
267 : }
268 :
269 19984 : ret = cpydata(data, data_size, &pdata);
270 19984 : if (ret < 0) {
271 1233 : gnutls_assert();
272 1233 : return ret;
273 : }
274 :
275 18751 : base64_decode_init(&ctx);
276 :
277 18751 : size = BASE64_DECODE_LENGTH(pdata.size);
278 18751 : if (size == 0) {
279 0 : ret = gnutls_assert_val(GNUTLS_E_BASE64_DECODING_ERROR);
280 0 : goto cleanup;
281 : }
282 :
283 18751 : result->data = gnutls_malloc(size);
284 18751 : if (result->data == NULL) {
285 0 : ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
286 0 : goto cleanup;
287 : }
288 :
289 37502 : ret = base64_decode_update(&ctx, &size, result->data,
290 18751 : pdata.size, (void*)pdata.data);
291 18751 : if (ret == 0 || size == 0) {
292 645 : gnutls_assert();
293 645 : ret = GNUTLS_E_BASE64_DECODING_ERROR;
294 645 : goto fail;
295 : }
296 :
297 18106 : ret = base64_decode_final(&ctx);
298 18106 : if (ret != 1) {
299 490 : ret = gnutls_assert_val(GNUTLS_E_BASE64_DECODING_ERROR);
300 490 : goto fail;
301 : }
302 :
303 17616 : result->size = size;
304 :
305 17616 : ret = size;
306 17616 : goto cleanup;
307 :
308 1135 : fail:
309 1135 : gnutls_free(result->data);
310 :
311 18751 : cleanup:
312 18751 : gnutls_free(pdata.data);
313 18751 : return ret;
314 : }
315 :
316 :
317 : /* Searches the given string for ONE PEM encoded certificate, and
318 : * stores it in the result.
319 : *
320 : * The result_size (always non-zero) is the return value,
321 : * or a negative error code.
322 : */
323 : #define ENDSTR "-----"
324 : int
325 20544 : _gnutls_fbase64_decode(const char *header, const uint8_t * data,
326 : size_t data_size, gnutls_datum_t * result)
327 : {
328 20544 : int ret;
329 20544 : static const char top[] = "-----BEGIN ";
330 20544 : static const char bottom[] = "-----END ";
331 20544 : uint8_t *rdata, *kdata;
332 20544 : int rdata_size;
333 20544 : char pem_header[128];
334 :
335 20544 : _gnutls_str_cpy(pem_header, sizeof(pem_header), top);
336 20544 : if (header != NULL)
337 20440 : _gnutls_str_cat(pem_header, sizeof(pem_header), header);
338 :
339 20544 : rdata = memmem(data, data_size, pem_header, strlen(pem_header));
340 20544 : if (rdata == NULL) {
341 392 : gnutls_assert();
342 392 : _gnutls_hard_log("Could not find '%s'\n", pem_header);
343 392 : return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
344 : }
345 :
346 20152 : data_size -= MEMSUB(rdata, data);
347 :
348 20152 : if (data_size < 4 + strlen(bottom)) {
349 2 : gnutls_assert();
350 2 : return GNUTLS_E_BASE64_DECODING_ERROR;
351 : }
352 :
353 20150 : kdata =
354 20150 : memmem(rdata + 1, data_size - 1, ENDSTR, sizeof(ENDSTR) - 1);
355 : /* allow CR as well.
356 : */
357 20150 : if (kdata == NULL) {
358 5 : gnutls_assert();
359 5 : _gnutls_hard_log("Could not find '%s'\n", ENDSTR);
360 5 : return GNUTLS_E_BASE64_DECODING_ERROR;
361 : }
362 20145 : data_size -= strlen(ENDSTR);
363 20145 : data_size -= MEMSUB(kdata, rdata);
364 :
365 20145 : rdata = kdata + strlen(ENDSTR);
366 :
367 : /* position is now after the ---BEGIN--- headers */
368 :
369 20145 : kdata = memmem(rdata, data_size, bottom, strlen(bottom));
370 20145 : if (kdata == NULL) {
371 24 : gnutls_assert();
372 24 : return GNUTLS_E_BASE64_DECODING_ERROR;
373 : }
374 :
375 : /* position of kdata is before the ----END--- footer
376 : */
377 20121 : rdata_size = MEMSUB(kdata, rdata);
378 :
379 20121 : if (rdata_size < 4) {
380 196 : gnutls_assert();
381 196 : return GNUTLS_E_BASE64_DECODING_ERROR;
382 : }
383 :
384 19925 : if ((ret = _gnutls_base64_decode(rdata, rdata_size, result)) < 0) {
385 2319 : gnutls_assert();
386 2319 : return GNUTLS_E_BASE64_DECODING_ERROR;
387 : }
388 :
389 : return ret;
390 : }
391 :
392 : /**
393 : * gnutls_pem_base64_decode:
394 : * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
395 : * @b64_data: contain the encoded data
396 : * @result: the place where decoded data will be copied
397 : * @result_size: holds the size of the result
398 : *
399 : * This function will decode the given encoded data. If the header
400 : * given is non %NULL this function will search for "-----BEGIN header"
401 : * and decode only this part. Otherwise it will decode the first PEM
402 : * packet found.
403 : *
404 : * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
405 : * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
406 : * not long enough, or 0 on success.
407 : **/
408 : int
409 48 : gnutls_pem_base64_decode(const char *header,
410 : const gnutls_datum_t * b64_data,
411 : unsigned char *result, size_t * result_size)
412 : {
413 48 : gnutls_datum_t res;
414 48 : int ret;
415 :
416 48 : ret =
417 48 : _gnutls_fbase64_decode(header, b64_data->data, b64_data->size,
418 : &res);
419 48 : if (ret < 0)
420 43 : return gnutls_assert_val(ret);
421 :
422 5 : if (result == NULL || *result_size < (unsigned) res.size) {
423 1 : gnutls_free(res.data);
424 1 : *result_size = res.size;
425 1 : return GNUTLS_E_SHORT_MEMORY_BUFFER;
426 : } else {
427 4 : memcpy(result, res.data, res.size);
428 4 : gnutls_free(res.data);
429 4 : *result_size = res.size;
430 : }
431 :
432 4 : return 0;
433 : }
434 :
435 : /**
436 : * gnutls_pem_base64_decode2:
437 : * @header: The PEM header (eg. CERTIFICATE)
438 : * @b64_data: contains the encoded data
439 : * @result: the location of decoded data
440 : *
441 : * This function will decode the given encoded data. The decoded data
442 : * will be allocated, and stored into result. If the header given is
443 : * non null this function will search for "-----BEGIN header" and
444 : * decode only this part. Otherwise it will decode the first PEM
445 : * packet found.
446 : *
447 : * You should use gnutls_free() to free the returned data.
448 : *
449 : * Note, that prior to GnuTLS 3.4.0 this function was available
450 : * under the name gnutls_pem_base64_decode_alloc(). There is
451 : * compatibility macro pointing to this function.
452 : *
453 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
454 : * an error code is returned.
455 : *
456 : * Since: 3.4.0
457 : **/
458 : int
459 152 : gnutls_pem_base64_decode2(const char *header,
460 : const gnutls_datum_t * b64_data,
461 : gnutls_datum_t * result)
462 : {
463 152 : int ret;
464 :
465 152 : if (result == NULL)
466 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
467 :
468 152 : ret =
469 152 : _gnutls_fbase64_decode(header, b64_data->data, b64_data->size,
470 : result);
471 152 : if (ret < 0)
472 50 : return gnutls_assert_val(ret);
473 :
474 : return 0;
475 : }
476 :
477 : /**
478 : * gnutls_base64_decode2:
479 : * @base64: contains the encoded data
480 : * @result: the location of decoded data
481 : *
482 : * This function will decode the given base64 encoded data. The decoded data
483 : * will be allocated, and stored into result.
484 : *
485 : * You should use gnutls_free() to free the returned data.
486 : *
487 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
488 : * an error code is returned.
489 : *
490 : * Since: 3.6.0
491 : **/
492 : int
493 57 : gnutls_base64_decode2(const gnutls_datum_t *base64,
494 : gnutls_datum_t *result)
495 : {
496 57 : int ret;
497 :
498 57 : ret = _gnutls_base64_decode(base64->data, base64->size, result);
499 57 : if (ret < 0) {
500 49 : return gnutls_assert_val(ret);
501 : }
502 :
503 : return 0;
504 : }
505 :
506 : /**
507 : * gnutls_base64_encode2:
508 : * @data: contains the raw data
509 : * @result: will hold the newly allocated encoded data
510 : *
511 : * This function will convert the given data to printable data, using
512 : * the base64 encoding. This function will allocate the required
513 : * memory to hold the encoded data.
514 : *
515 : * You should use gnutls_free() to free the returned data.
516 : *
517 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
518 : * an error code is returned.
519 : *
520 : * Since: 3.6.0
521 : **/
522 : int
523 18 : gnutls_base64_encode2(const gnutls_datum_t *data,
524 : gnutls_datum_t *result)
525 : {
526 18 : int ret;
527 :
528 18 : if (result == NULL)
529 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
530 :
531 18 : ret = _gnutls_fbase64_encode(NULL, data->data, data->size, result);
532 18 : if (ret < 0)
533 0 : return gnutls_assert_val(ret);
534 :
535 : return 0;
536 : }
|