enable useful extensions in the examples.
[gnutls.git] / lib / gnutls_str.c
blob34a8a1982992f869fd6a26857e7e38016126783a
1 /*
2 * Copyright (C) 2002-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 #include <gnutls_int.h>
24 #include <gnutls_errors.h>
25 #include <gnutls_num.h>
26 #include <gnutls_str.h>
27 #include <stdarg.h>
28 #include <c-ctype.h>
30 /* These function are like strcat, strcpy. They only
31 * do bound checking (they shouldn't cause buffer overruns),
32 * and they always produce null terminated strings.
34 * They should be used only with null terminated strings.
36 void
37 _gnutls_str_cat (char *dest, size_t dest_tot_size, const char *src)
39 size_t str_size = strlen (src);
40 size_t dest_size = strlen (dest);
42 if (dest_tot_size - dest_size > str_size)
44 strcat (dest, src);
46 else
48 if (dest_tot_size - dest_size > 0)
50 strncat (dest, src, (dest_tot_size - dest_size) - 1);
51 dest[dest_tot_size - 1] = 0;
56 void
57 _gnutls_str_cpy (char *dest, size_t dest_tot_size, const char *src)
59 size_t str_size = strlen (src);
61 if (dest_tot_size > str_size)
63 strcpy (dest, src);
65 else
67 if (dest_tot_size > 0)
69 strncpy (dest, src, (dest_tot_size) - 1);
70 dest[dest_tot_size - 1] = 0;
75 void
76 _gnutls_mem_cpy (char *dest, size_t dest_tot_size, const char *src,
77 size_t src_size)
80 if (dest_tot_size >= src_size)
82 memcpy (dest, src, src_size);
84 else
86 if (dest_tot_size > 0)
88 memcpy (dest, src, dest_tot_size);
93 void
94 _gnutls_buffer_init (gnutls_buffer_st * str)
96 str->data = str->allocd = NULL;
97 str->max_length = 0;
98 str->length = 0;
101 void _gnutls_buffer_replace_data( gnutls_buffer_st * buf, gnutls_datum_t * data)
103 gnutls_free(buf->allocd);
104 buf->allocd = buf->data = data->data;
105 buf->max_length = buf->length = data->size;
108 void
109 _gnutls_buffer_clear (gnutls_buffer_st * str)
111 if (str == NULL || str->allocd == NULL)
112 return;
113 gnutls_free (str->allocd);
115 str->data = str->allocd = NULL;
116 str->max_length = 0;
117 str->length = 0;
120 #define MIN_CHUNK 1024
123 _gnutls_buffer_append_data (gnutls_buffer_st * dest, const void *data,
124 size_t data_size)
126 size_t tot_len = data_size + dest->length;
128 if (data_size == 0) return 0;
130 if (dest->max_length >= tot_len)
132 size_t unused = MEMSUB (dest->data, dest->allocd);
134 if (dest->max_length - unused <= tot_len)
136 if (dest->length && dest->data)
137 memmove (dest->allocd, dest->data, dest->length);
139 dest->data = dest->allocd;
141 memmove (&dest->data[dest->length], data, data_size);
142 dest->length = tot_len;
144 return tot_len;
146 else
148 size_t unused = MEMSUB (dest->data, dest->allocd);
149 size_t new_len =
150 MAX (data_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK);
152 dest->allocd = gnutls_realloc (dest->allocd, new_len);
153 if (dest->allocd == NULL)
155 gnutls_assert ();
156 return GNUTLS_E_MEMORY_ERROR;
158 dest->max_length = new_len;
159 dest->data = dest->allocd + unused;
161 if (dest->length && dest->data)
162 memmove (dest->allocd, dest->data, dest->length);
163 dest->data = dest->allocd;
165 memcpy (&dest->data[dest->length], data, data_size);
166 dest->length = tot_len;
168 return tot_len;
173 _gnutls_buffer_resize (gnutls_buffer_st * dest, size_t new_size)
175 if (dest->max_length >= new_size)
177 size_t unused = MEMSUB (dest->data, dest->allocd);
178 if (dest->max_length - unused <= new_size)
180 if (dest->length && dest->data)
181 memmove (dest->allocd, dest->data, dest->length);
182 dest->data = dest->allocd;
185 return 0;
187 else
189 size_t unused = MEMSUB (dest->data, dest->allocd);
190 size_t alloc_len =
191 MAX (new_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK);
193 dest->allocd = gnutls_realloc (dest->allocd, alloc_len);
194 if (dest->allocd == NULL)
196 gnutls_assert ();
197 return GNUTLS_E_MEMORY_ERROR;
199 dest->max_length = alloc_len;
200 dest->data = dest->allocd + unused;
202 if (dest->length && dest->data)
203 memmove (dest->allocd, dest->data, dest->length);
204 dest->data = dest->allocd;
206 return 0;
210 /* Appends the provided string. The null termination byte is appended
211 * but not included in length.
214 _gnutls_buffer_append_str (gnutls_buffer_st * dest, const char *src)
216 int ret;
217 ret = _gnutls_buffer_append_data (dest, src, strlen (src) + 1);
218 if (ret >= 0) dest->length--;
220 return ret;
223 /* returns data from a string in a constant buffer.
224 * The data will NOT be valid if buffer is released or
225 * data are appended in the buffer.
227 void
228 _gnutls_buffer_pop_datum (gnutls_buffer_st * str, gnutls_datum_t * data,
229 size_t req_size)
232 if (str->length == 0)
234 data->data = NULL;
235 data->size = 0;
236 return;
239 if (req_size > str->length)
240 req_size = str->length;
242 data->data = str->data;
243 data->size = req_size;
245 str->data += req_size;
246 str->length -= req_size;
248 /* if string becomes empty start from begining */
249 if (str->length == 0)
251 str->data = str->allocd;
254 return;
257 /* converts the buffer to a datum if possible. After this call
258 * (failed or not) the buffer should be considered deinitialized.
261 _gnutls_buffer_to_datum (gnutls_buffer_st * str, gnutls_datum_t * data)
264 if (str->length == 0)
266 data->data = NULL;
267 data->size = 0;
268 _gnutls_buffer_clear (str);
269 return 0;
272 if (str->allocd != str->data)
274 data->data = gnutls_malloc (str->length);
275 if (data->data == NULL)
277 gnutls_assert ();
278 _gnutls_buffer_clear (str);
279 return GNUTLS_E_MEMORY_ERROR;
281 memcpy (data->data, str->data, str->length);
282 data->size = str->length;
283 _gnutls_buffer_clear (str);
285 else
287 data->data = str->data;
288 data->size = str->length;
289 _gnutls_buffer_init(str);
292 return 0;
295 /* returns data from a string in a constant buffer.
297 void
298 _gnutls_buffer_pop_data (gnutls_buffer_st * str, void *data,
299 size_t * req_size)
301 gnutls_datum_t tdata;
303 _gnutls_buffer_pop_datum (str, &tdata, *req_size);
305 *req_size = tdata.size;
306 memcpy (data, tdata.data, tdata.size);
308 return;
312 _gnutls_buffer_append_printf (gnutls_buffer_st * dest, const char *fmt, ...)
314 va_list args;
315 int len;
316 char *str;
318 va_start (args, fmt);
319 len = vasprintf (&str, fmt, args);
320 va_end (args);
322 if (len < 0 || !str)
323 return -1;
325 len = _gnutls_buffer_append_str (dest, str);
327 free (str);
329 return len;
332 static int
333 _gnutls_buffer_insert_data (gnutls_buffer_st * dest, int pos, const void *str,
334 size_t str_size)
336 size_t orig_length = dest->length;
337 int ret;
339 ret = _gnutls_buffer_resize (dest, dest->length + str_size); /* resize to make space */
340 if (ret < 0)
341 return ret;
343 memmove (&dest->data[pos + str_size], &dest->data[pos], orig_length - pos);
345 memcpy (&dest->data[pos], str, str_size);
346 dest->length += str_size;
348 return 0;
351 static void
352 _gnutls_buffer_delete_data (gnutls_buffer_st * dest, int pos, size_t str_size)
354 memmove (&dest->data[pos], &dest->data[pos + str_size],
355 dest->length - pos - str_size);
357 dest->length -= str_size;
359 return;
364 _gnutls_buffer_escape (gnutls_buffer_st * dest, int all,
365 const char *const invalid_chars)
367 int rv = -1;
368 char t[5];
369 unsigned int pos = 0;
371 while (pos < dest->length)
374 if (all != 0 || (dest->data[pos] == '\\' || strchr (invalid_chars, dest->data[pos])
375 || !c_isgraph (dest->data[pos])))
378 snprintf (t, sizeof (t), "%%%.2X", (unsigned int) dest->data[pos]);
380 _gnutls_buffer_delete_data (dest, pos, 1);
382 if (_gnutls_buffer_insert_data (dest, pos, t, 3) < 0)
384 rv = -1;
385 goto cleanup;
387 pos+=3;
389 else
390 pos++;
393 rv = 0;
395 cleanup:
397 return rv;
401 _gnutls_buffer_unescape (gnutls_buffer_st * dest)
403 int rv = -1;
404 unsigned int pos = 0;
406 while (pos < dest->length)
408 if (dest->data[pos] == '%')
410 char b[3];
411 unsigned int u;
412 unsigned char x;
414 b[0] = dest->data[pos + 1];
415 b[1] = dest->data[pos + 2];
416 b[2] = 0;
418 sscanf (b, "%02x", &u);
420 x = u;
422 _gnutls_buffer_delete_data (dest, pos, 3);
423 _gnutls_buffer_insert_data (dest, pos, &x, 1);
425 pos++;
428 rv = 0;
430 return rv;
434 /* Converts the given string (old) to hex. A buffer must be provided
435 * to hold the new hex string. The new string will be null terminated.
436 * If the buffer does not have enough space to hold the string, a
437 * truncated hex string is returned (always null terminated).
439 char *
440 _gnutls_bin2hex (const void *_old, size_t oldlen,
441 char *buffer, size_t buffer_size, const char *separator)
443 unsigned int i, j;
444 const uint8_t *old = _old;
445 int step = 2;
446 const char empty[] = "";
448 if (separator != NULL && separator[0] != 0)
449 step = 3;
450 else
451 separator = empty;
453 if (buffer_size < 3)
455 gnutls_assert();
456 return NULL;
459 i = j = 0;
460 sprintf (&buffer[j], "%.2x", old[i]);
461 j += 2;
462 i++;
464 for (; i < oldlen && j + step < buffer_size; j += step)
466 sprintf (&buffer[j], "%s%.2x", separator, old[i]);
467 i++;
469 buffer[j] = '\0';
471 return buffer;
475 * gnutls_hex2bin:
476 * @hex_data: string with data in hex format
477 * @hex_size: size of hex data
478 * @bin_data: output array with binary data
479 * @bin_size: when calling should hold maximum size of @bin_data,
480 * on return will hold actual length of @bin_data.
482 * Convert a buffer with hex data to binary data.
484 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
486 * Since: 2.4.0
489 gnutls_hex2bin (const char *hex_data,
490 size_t hex_size, void *bin_data, size_t * bin_size)
492 return _gnutls_hex2bin (hex_data, hex_size, (void*)bin_data, bin_size);
496 _gnutls_hex2bin (const char * hex_data, size_t hex_size, uint8_t * bin_data,
497 size_t * bin_size)
499 unsigned int i, j;
500 uint8_t hex2_data[3];
501 unsigned long val;
503 hex2_data[2] = 0;
505 for (i = j = 0; i < hex_size;)
507 if (!isxdigit (hex_data[i])) /* skip non-hex such as the ':' in 00:FF */
509 i++;
510 continue;
513 if (j > *bin_size)
515 gnutls_assert ();
516 return GNUTLS_E_SHORT_MEMORY_BUFFER;
519 hex2_data[0] = hex_data[i];
520 hex2_data[1] = hex_data[i + 1];
521 i += 2;
523 val = strtoul ((char *) hex2_data, NULL, 16);
524 if (val == ULONG_MAX)
526 gnutls_assert ();
527 return GNUTLS_E_PARSING_ERROR;
529 bin_data[j] = val;
530 j++;
532 *bin_size = j;
534 return 0;
538 /* compare hostname against certificate, taking account of wildcards
539 * return 1 on success or 0 on error
541 * note: certnamesize is required as X509 certs can contain embedded NULs in
542 * the strings such as CN or subjectAltName.
544 * @level: is used for recursion. Use 0 when you call this function.
547 _gnutls_hostname_compare (const char *certname,
548 size_t certnamesize, const char *hostname, int level)
551 if (level > 5)
552 return 0;
554 /* find the first different character */
555 for (; *certname && *hostname && c_toupper (*certname) == c_toupper (*hostname);
556 certname++, hostname++, certnamesize--)
559 /* the strings are the same */
560 if (certnamesize == 0 && *hostname == '\0')
561 return 1;
563 if (*certname == '*')
565 /* a wildcard certificate */
567 certname++;
568 certnamesize--;
570 while (1)
572 /* Use a recursive call to allow multiple wildcards */
573 if (_gnutls_hostname_compare (certname, certnamesize, hostname, level+1))
574 return 1;
576 /* wildcards are only allowed to match a single domain
577 component or component fragment */
578 if (*hostname == '\0' || *hostname == '.')
579 break;
580 hostname++;
583 return 0;
586 return 0;
590 _gnutls_buffer_append_prefix (gnutls_buffer_st * buf, int pfx_size, size_t data_size)
592 uint8_t ss[4];
594 if (pfx_size == 32)
596 _gnutls_write_uint32 (data_size, ss);
597 pfx_size = 4;
599 else if (pfx_size == 24)
601 _gnutls_write_uint24 (data_size, ss);
602 pfx_size = 3;
604 else if (pfx_size == 16)
606 _gnutls_write_uint16 (data_size, ss);
607 pfx_size = 2;
609 else if (pfx_size == 8)
611 ss[0] = data_size;
612 pfx_size = 1;
614 else
615 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
617 return _gnutls_buffer_append_data (buf, ss, pfx_size);
620 /* Reads an uint32 number from the buffer. If check is non zero it will also check whether
621 * the number read, is less than the data in the buffer
624 _gnutls_buffer_pop_prefix (gnutls_buffer_st * buf, size_t * data_size,
625 int check)
627 size_t size;
629 if (buf->length < 4)
631 gnutls_assert ();
632 return GNUTLS_E_PARSING_ERROR;
635 size = _gnutls_read_uint32 (buf->data);
636 if (check && size > buf->length - 4)
638 gnutls_assert ();
639 return GNUTLS_E_PARSING_ERROR;
642 buf->data += 4;
643 buf->length -= 4;
645 *data_size = size;
647 return 0;
651 _gnutls_buffer_pop_datum_prefix (gnutls_buffer_st * buf,
652 gnutls_datum_t * data)
654 size_t size;
655 int ret;
657 ret = _gnutls_buffer_pop_prefix (buf, &size, 1);
658 if (ret < 0)
660 gnutls_assert ();
661 return ret;
664 if (size > 0)
666 size_t osize = size;
667 _gnutls_buffer_pop_datum (buf, data, size);
668 if (osize != data->size)
670 gnutls_assert ();
671 return GNUTLS_E_PARSING_ERROR;
674 else
676 data->size = 0;
677 data->data = NULL;
680 return 0;
684 _gnutls_buffer_append_data_prefix (gnutls_buffer_st * buf,
685 int pfx_size, const void *data, size_t data_size)
687 int ret = 0, ret1;
689 ret1 = _gnutls_buffer_append_prefix (buf, pfx_size, data_size);
690 if (ret1 < 0)
691 return gnutls_assert_val(ret1);
693 if (data_size > 0)
695 ret = _gnutls_buffer_append_data (buf, data, data_size);
697 if (ret < 0)
698 return gnutls_assert_val(ret);
701 return ret + ret1;
704 int _gnutls_buffer_append_mpi (gnutls_buffer_st * buf, int pfx_size, bigint_t mpi, int lz)
706 gnutls_datum_t dd;
707 int ret;
709 if (lz)
710 ret = _gnutls_mpi_dprint_lz (mpi, &dd);
711 else
712 ret = _gnutls_mpi_dprint (mpi, &dd);
714 if (ret < 0)
715 return gnutls_assert_val(ret);
717 ret = _gnutls_buffer_append_data_prefix(buf, pfx_size, dd.data, dd.size);
719 _gnutls_free_datum(&dd);
721 return ret;
725 _gnutls_buffer_pop_data_prefix (gnutls_buffer_st * buf, void *data,
726 size_t * data_size)
728 size_t size;
729 int ret;
731 ret = _gnutls_buffer_pop_prefix (buf, &size, 1);
732 if (ret < 0)
734 gnutls_assert ();
735 return ret;
738 if (size > 0)
739 _gnutls_buffer_pop_data (buf, data, data_size);
741 return 0;
744 void
745 _gnutls_buffer_hexprint (gnutls_buffer_st * str,
746 const void *_data, size_t len)
748 size_t j;
749 const unsigned char* data = _data;
751 if (len == 0)
752 _gnutls_buffer_append_str (str, "00");
753 else
755 for (j = 0; j < len; j++)
756 _gnutls_buffer_append_printf (str, "%.2x", (unsigned) data[j]);
760 void
761 _gnutls_buffer_hexdump (gnutls_buffer_st * str, const void *_data, size_t len,
762 const char *spc)
764 size_t j;
765 const unsigned char* data = _data;
767 if (spc)
768 _gnutls_buffer_append_str (str, spc);
769 for (j = 0; j < len; j++)
771 if (((j + 1) % 16) == 0)
773 _gnutls_buffer_append_printf (str, "%.2x\n", (unsigned)data[j]);
774 if (spc && j != (len - 1))
775 _gnutls_buffer_append_str (str, spc);
777 else if (j == (len - 1))
778 _gnutls_buffer_append_printf (str, "%.2x", (unsigned)data[j]);
779 else
780 _gnutls_buffer_append_printf (str, "%.2x:", (unsigned)data[j]);
782 if ((j % 16) != 0)
783 _gnutls_buffer_append_str (str, "\n");
786 void
787 _gnutls_buffer_asciiprint (gnutls_buffer_st * str,
788 const char *data, size_t len)
790 size_t j;
792 for (j = 0; j < len; j++)
793 if (c_isprint (data[j]))
794 _gnutls_buffer_append_printf (str, "%c", (unsigned char) data[j]);
795 else
796 _gnutls_buffer_append_printf (str, ".");