Removed incorrect test on IPAddresses (was relying on IPaddresses encoded as text)
[gnutls.git] / lib / gnutls_str.c
blob4b6fc634bd5730d78c29f0a9d596529eb6245627
1 /*
2 * Copyright (C) 2002, 2004, 2005, 2007, 2008, 2009, 2010 Free Software
3 * Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
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.
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.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 #include <gnutls_int.h>
27 #include <gnutls_errors.h>
28 #include <gnutls_num.h>
29 #include <gnutls_str.h>
30 #include <stdarg.h>
32 /* These function are like strcat, strcpy. They only
33 * do bound checking (they shouldn't cause buffer overruns),
34 * and they always produce null terminated strings.
36 * They should be used only with null terminated strings.
38 void
39 _gnutls_str_cat (char *dest, size_t dest_tot_size, const char *src)
41 size_t str_size = strlen (src);
42 size_t dest_size = strlen (dest);
44 if (dest_tot_size - dest_size > str_size)
46 strcat (dest, src);
48 else
50 if (dest_tot_size - dest_size > 0)
52 strncat (dest, src, (dest_tot_size - dest_size) - 1);
53 dest[dest_tot_size - 1] = 0;
58 void
59 _gnutls_str_cpy (char *dest, size_t dest_tot_size, const char *src)
61 size_t str_size = strlen (src);
63 if (dest_tot_size > str_size)
65 strcpy (dest, src);
67 else
69 if (dest_tot_size > 0)
71 strncpy (dest, src, (dest_tot_size) - 1);
72 dest[dest_tot_size - 1] = 0;
77 void
78 _gnutls_mem_cpy (char *dest, size_t dest_tot_size, const char *src,
79 size_t src_size)
82 if (dest_tot_size >= src_size)
84 memcpy (dest, src, src_size);
86 else
88 if (dest_tot_size > 0)
90 memcpy (dest, src, dest_tot_size);
95 void
96 _gnutls_buffer_init (gnutls_buffer_st * str)
98 str->data = str->allocd = NULL;
99 str->max_length = 0;
100 str->length = 0;
103 void
104 _gnutls_buffer_clear (gnutls_buffer_st * str)
106 if (str == NULL || str->allocd == NULL)
107 return;
108 gnutls_free (str->allocd);
110 str->data = str->allocd = NULL;
111 str->max_length = 0;
112 str->length = 0;
115 #define MIN_CHUNK 1024
118 _gnutls_buffer_append_data (gnutls_buffer_st * dest, const void *data,
119 size_t data_size)
121 size_t tot_len = data_size + dest->length;
123 if (dest->max_length >= tot_len)
125 size_t unused = MEMSUB (dest->data, dest->allocd);
127 if (dest->max_length - unused <= tot_len)
129 if (dest->length && dest->data)
130 memmove (dest->allocd, dest->data, dest->length);
132 dest->data = dest->allocd;
134 memmove (&dest->data[dest->length], data, data_size);
135 dest->length = tot_len;
137 return tot_len;
139 else
141 size_t unused = MEMSUB (dest->data, dest->allocd);
142 size_t new_len =
143 MAX (data_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK);
145 dest->allocd = gnutls_realloc (dest->allocd, new_len);
146 if (dest->allocd == NULL)
148 gnutls_assert ();
149 return GNUTLS_E_MEMORY_ERROR;
151 dest->max_length = new_len;
152 dest->data = dest->allocd + unused;
154 if (dest->length && dest->data)
155 memmove (dest->allocd, dest->data, dest->length);
156 dest->data = dest->allocd;
158 memcpy (&dest->data[dest->length], data, data_size);
159 dest->length = tot_len;
161 return tot_len;
166 _gnutls_buffer_resize (gnutls_buffer_st * dest, size_t new_size)
168 if (dest->max_length >= new_size)
170 size_t unused = MEMSUB (dest->data, dest->allocd);
171 if (dest->max_length - unused <= new_size)
173 if (dest->length && dest->data)
174 memmove (dest->allocd, dest->data, dest->length);
175 dest->data = dest->allocd;
178 return 0;
180 else
182 size_t unused = MEMSUB (dest->data, dest->allocd);
183 size_t alloc_len =
184 MAX (new_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK);
186 dest->allocd = gnutls_realloc (dest->allocd, alloc_len);
187 if (dest->allocd == NULL)
189 gnutls_assert ();
190 return GNUTLS_E_MEMORY_ERROR;
192 dest->max_length = alloc_len;
193 dest->data = dest->allocd + unused;
195 if (dest->length && dest->data)
196 memmove (dest->allocd, dest->data, dest->length);
197 dest->data = dest->allocd;
199 return 0;
204 _gnutls_buffer_append_str (gnutls_buffer_st * dest, const char *src)
206 return _gnutls_buffer_append_data (dest, src, strlen (src));
209 /* returns data from a string in a constant buffer.
210 * The data will NOT be valid if buffer is released or
211 * data are appended in the buffer.
213 void
214 _gnutls_buffer_pop_datum (gnutls_buffer_st * str, gnutls_datum_t * data,
215 size_t req_size)
218 if (str->length == 0)
220 data->data = NULL;
221 data->size = 0;
222 return;
225 if (req_size > str->length)
226 req_size = str->length;
228 data->data = str->data;
229 data->size = req_size;
231 str->data += req_size;
232 str->length -= req_size;
234 /* if string becomes empty start from begining */
235 if (str->length == 0)
237 str->data = str->allocd;
240 return;
243 /* converts the buffer to a datum if possible. After this call the buffer
244 * is at an usable state and might not be used or deinitialized */
246 _gnutls_buffer_to_datum (gnutls_buffer_st * str, gnutls_datum_t * data)
249 if (str->length == 0)
251 data->data = NULL;
252 data->size = 0;
253 return 0;
256 if (str->allocd != str->data)
258 data->data = gnutls_malloc (str->length);
259 if (data->data == NULL)
261 gnutls_assert ();
262 return GNUTLS_E_MEMORY_ERROR;
264 memcpy (data->data, str->data, str->length);
265 data->size = str->length;
266 _gnutls_buffer_clear (str);
268 else
270 data->data = str->data;
271 data->size = str->length;
274 return 0;
277 /* returns data from a string in a constant buffer.
279 void
280 _gnutls_buffer_pop_data (gnutls_buffer_st * str, void *data,
281 size_t * req_size)
283 gnutls_datum_t tdata;
285 _gnutls_buffer_pop_datum (str, &tdata, *req_size);
287 *req_size = tdata.size;
288 memcpy (data, tdata.data, tdata.size);
290 return;
294 _gnutls_buffer_append_printf (gnutls_buffer_st * dest, const char *fmt, ...)
296 va_list args;
297 int len;
298 char *str;
300 va_start (args, fmt);
301 len = vasprintf (&str, fmt, args);
302 va_end (args);
304 if (len < 0 || !str)
305 return -1;
307 len = _gnutls_buffer_append_str (dest, str);
309 free (str);
311 return len;
314 static int
315 _gnutls_buffer_insert_data (gnutls_buffer_st * dest, int pos, const void *str,
316 size_t str_size)
318 size_t orig_length = dest->length;
319 int ret;
321 ret = _gnutls_buffer_resize (dest, dest->length + str_size); /* resize to make space */
322 if (ret < 0)
323 return ret;
325 memmove (&dest->data[pos + str_size], &dest->data[pos], orig_length - pos);
327 memcpy (&dest->data[pos], str, str_size);
328 dest->length += str_size;
330 return 0;
333 static void
334 _gnutls_buffer_delete_data (gnutls_buffer_st * dest, int pos, size_t str_size)
336 memmove (&dest->data[pos], &dest->data[pos + str_size],
337 dest->length - pos - str_size);
339 dest->length -= str_size;
341 return;
346 _gnutls_buffer_escape (gnutls_buffer_st * dest,
347 const char *const invalid_chars)
349 int rv = -1;
350 char t[5];
351 int pos = 0;
353 while (pos < dest->length)
356 if (dest->data[pos] == '\\' || strchr (invalid_chars, dest->data[pos])
357 || !isgraph (dest->data[pos]))
360 snprintf (t, sizeof (t), "%%%.2X", (unsigned int) dest->data[pos]);
362 _gnutls_buffer_delete_data (dest, pos, 1);
364 if (_gnutls_buffer_insert_data (dest, pos, t, 3) < 0)
366 rv = -1;
367 goto cleanup;
371 pos++;
374 rv = 0;
376 cleanup:
378 return rv;
382 _gnutls_buffer_unescape (gnutls_buffer_st * dest)
384 int rv = -1;
385 int pos = 0;
387 while (pos < dest->length)
389 if (dest->data[pos] == '%')
391 char b[3];
392 unsigned int u;
393 unsigned char x;
395 b[0] = dest->data[pos + 1];
396 b[1] = dest->data[pos + 2];
397 b[2] = 0;
399 sscanf (b, "%02x", &u);
401 x = u;
403 _gnutls_buffer_delete_data (dest, pos, 3);
404 _gnutls_buffer_insert_data (dest, pos, &x, 1);
406 pos++;
409 rv = 0;
411 return rv;
415 /* Converts the given string (old) to hex. A buffer must be provided
416 * to hold the new hex string. The new string will be null terminated.
417 * If the buffer does not have enough space to hold the string, a
418 * truncated hex string is returned (always null terminated).
420 char *
421 _gnutls_bin2hex (const void *_old, size_t oldlen,
422 char *buffer, size_t buffer_size, const char *separator)
424 unsigned int i, j;
425 const opaque *old = _old;
426 int step = 2;
427 const char empty[] = "";
429 if (separator != NULL && separator[0] != 0)
430 step = 3;
431 else
432 separator = empty;
434 if (buffer_size < 3)
436 gnutls_assert();
437 return NULL;
440 i = j = 0;
441 sprintf (&buffer[j], "%.2x", old[i]);
442 j += 2;
443 i++;
445 for (; i < oldlen && j + step < buffer_size; j += step)
447 sprintf (&buffer[j], "%s%.2x", separator, old[i]);
448 i++;
450 buffer[j] = '\0';
452 return buffer;
456 * gnutls_hex2bin:
457 * @hex_data: string with data in hex format
458 * @hex_size: size of hex data
459 * @bin_data: output array with binary data
460 * @bin_size: when calling *@bin_size should hold size of @bin_data,
461 * on return will hold actual size of @bin_data.
463 * Convert a buffer with hex data to binary data.
465 * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
467 * Since: 2.4.0
470 gnutls_hex2bin (const char *hex_data,
471 size_t hex_size, char *bin_data, size_t * bin_size)
473 return _gnutls_hex2bin (hex_data, (int) hex_size, bin_data, bin_size);
477 _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data,
478 size_t * bin_size)
480 int i, j;
481 opaque hex2_data[3];
482 unsigned long val;
484 hex2_data[2] = 0;
486 for (i = j = 0; i < hex_size;)
488 if (!isxdigit (hex_data[i])) /* skip non-hex such as the ':' in 00:FF */
490 i++;
491 continue;
494 if (j > *bin_size)
496 gnutls_assert ();
497 return GNUTLS_E_SHORT_MEMORY_BUFFER;
500 hex2_data[0] = hex_data[i];
501 hex2_data[1] = hex_data[i + 1];
502 i += 2;
504 val = strtoul ((char *) hex2_data, NULL, 16);
505 if (val == ULONG_MAX)
507 gnutls_assert ();
508 return GNUTLS_E_PARSING_ERROR;
510 bin_data[j] = val;
511 j++;
513 *bin_size = j;
515 return 0;
519 /* compare hostname against certificate, taking account of wildcards
520 * return 1 on success or 0 on error
522 * note: certnamesize is required as X509 certs can contain embedded NULs in
523 * the strings such as CN or subjectAltName
526 _gnutls_hostname_compare (const char *certname,
527 size_t certnamesize, const char *hostname)
529 /* find the first different character */
530 for (; *certname && *hostname && toupper (*certname) == toupper (*hostname);
531 certname++, hostname++, certnamesize--)
534 /* the strings are the same */
535 if (certnamesize == 0 && *hostname == '\0')
536 return 1;
538 if (*certname == '*')
540 /* a wildcard certificate */
542 certname++;
543 certnamesize--;
545 while (1)
547 /* Use a recursive call to allow multiple wildcards */
548 if (_gnutls_hostname_compare (certname, certnamesize, hostname))
549 return 1;
551 /* wildcards are only allowed to match a single domain
552 component or component fragment */
553 if (*hostname == '\0' || *hostname == '.')
554 break;
555 hostname++;
558 return 0;
561 return 0;
565 _gnutls_buffer_append_prefix (gnutls_buffer_st * buf, size_t data_size)
567 opaque ss[4];
568 _gnutls_write_uint32 (data_size, ss);
569 return _gnutls_buffer_append_data (buf, ss, 4);
572 /* Reads an uint32 number from the buffer. If check is non zero it will also check whether
573 * the number read, is less than the data in the buffer
576 _gnutls_buffer_pop_prefix (gnutls_buffer_st * buf, size_t * data_size,
577 int check)
579 size_t size;
581 if (buf->length < 4)
583 gnutls_assert ();
584 return GNUTLS_E_PARSING_ERROR;
587 size = _gnutls_read_uint32 (buf->data);
588 if (check && size > buf->length - 4)
590 gnutls_assert ();
591 return GNUTLS_E_PARSING_ERROR;
594 buf->data += 4;
595 buf->length -= 4;
597 *data_size = size;
599 return 0;
603 _gnutls_buffer_pop_datum_prefix (gnutls_buffer_st * buf,
604 gnutls_datum_t * data)
606 size_t size;
607 int ret;
609 ret = _gnutls_buffer_pop_prefix (buf, &size, 1);
610 if (ret < 0)
612 gnutls_assert ();
613 return ret;
616 if (size > 0)
618 size_t osize = size;
619 _gnutls_buffer_pop_datum (buf, data, size);
620 if (osize != data->size)
622 gnutls_assert ();
623 return GNUTLS_E_PARSING_ERROR;
626 else
628 data->size = 0;
629 data->data = NULL;
632 return 0;
636 _gnutls_buffer_append_data_prefix (gnutls_buffer_st * buf, const void *data,
637 size_t data_size)
639 _gnutls_buffer_append_prefix (buf, data_size);
640 if (data_size > 0)
641 return _gnutls_buffer_append_data (buf, data, data_size);
643 return 0;
647 _gnutls_buffer_pop_data_prefix (gnutls_buffer_st * buf, void *data,
648 size_t * data_size)
650 size_t size;
651 int ret;
653 ret = _gnutls_buffer_pop_prefix (buf, &size, 1);
654 if (ret < 0)
656 gnutls_assert ();
657 return ret;
660 if (size > 0)
661 _gnutls_buffer_pop_data (buf, data, data_size);
663 return 0;