Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_str.c
1 /*
2  * Copyright (C) 2002, 2004, 2005, 2007, 2008, 2009, 2010 Free Software
3  * Foundation, 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
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
23  *
24  */
25
26 #include <gnutls_int.h>
27 #include <gnutls_errors.h>
28 #include <gnutls_num.h>
29 #include <gnutls_str.h>
30 #include <stdarg.h>
31 #include <c-ctype.h>
32
33 /* These function are like strcat, strcpy. They only
34  * do bound checking (they shouldn't cause buffer overruns),
35  * and they always produce null terminated strings.
36  *
37  * They should be used only with null terminated strings.
38  */
39 void
40 _gnutls_str_cat (char *dest, size_t dest_tot_size, const char *src)
41 {
42   size_t str_size = strlen (src);
43   size_t dest_size = strlen (dest);
44
45   if (dest_tot_size - dest_size > str_size)
46     {
47       strcat (dest, src);
48     }
49   else
50     {
51       if (dest_tot_size - dest_size > 0)
52         {
53           strncat (dest, src, (dest_tot_size - dest_size) - 1);
54           dest[dest_tot_size - 1] = 0;
55         }
56     }
57 }
58
59 void
60 _gnutls_str_cpy (char *dest, size_t dest_tot_size, const char *src)
61 {
62   size_t str_size = strlen (src);
63
64   if (dest_tot_size > str_size)
65     {
66       strcpy (dest, src);
67     }
68   else
69     {
70       if (dest_tot_size > 0)
71         {
72           strncpy (dest, src, (dest_tot_size) - 1);
73           dest[dest_tot_size - 1] = 0;
74         }
75     }
76 }
77
78 void
79 _gnutls_mem_cpy (char *dest, size_t dest_tot_size, const char *src,
80                  size_t src_size)
81 {
82
83   if (dest_tot_size >= src_size)
84     {
85       memcpy (dest, src, src_size);
86     }
87   else
88     {
89       if (dest_tot_size > 0)
90         {
91           memcpy (dest, src, dest_tot_size);
92         }
93     }
94 }
95
96 void
97 _gnutls_buffer_init (gnutls_buffer_st * str)
98 {
99   str->data = str->allocd = NULL;
100   str->max_length = 0;
101   str->length = 0;
102 }
103
104 void
105 _gnutls_buffer_clear (gnutls_buffer_st * str)
106 {
107   if (str == NULL || str->allocd == NULL)
108     return;
109   gnutls_free (str->allocd);
110
111   str->data = str->allocd = NULL;
112   str->max_length = 0;
113   str->length = 0;
114 }
115
116 #define MIN_CHUNK 1024
117
118 int
119 _gnutls_buffer_append_data (gnutls_buffer_st * dest, const void *data,
120                             size_t data_size)
121 {
122   size_t tot_len = data_size + dest->length;
123
124   if (dest->max_length >= tot_len)
125     {
126       size_t unused = MEMSUB (dest->data, dest->allocd);
127
128       if (dest->max_length - unused <= tot_len)
129         {
130           if (dest->length && dest->data)
131             memmove (dest->allocd, dest->data, dest->length);
132
133           dest->data = dest->allocd;
134         }
135       memmove (&dest->data[dest->length], data, data_size);
136       dest->length = tot_len;
137
138       return tot_len;
139     }
140   else
141     {
142       size_t unused = MEMSUB (dest->data, dest->allocd);
143       size_t new_len =
144         MAX (data_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK);
145
146       dest->allocd = gnutls_realloc (dest->allocd, new_len);
147       if (dest->allocd == NULL)
148         {
149           gnutls_assert ();
150           return GNUTLS_E_MEMORY_ERROR;
151         }
152       dest->max_length = new_len;
153       dest->data = dest->allocd + unused;
154
155       if (dest->length && dest->data)
156         memmove (dest->allocd, dest->data, dest->length);
157       dest->data = dest->allocd;
158
159       memcpy (&dest->data[dest->length], data, data_size);
160       dest->length = tot_len;
161
162       return tot_len;
163     }
164 }
165
166 int
167 _gnutls_buffer_resize (gnutls_buffer_st * dest, size_t new_size)
168 {
169   if (dest->max_length >= new_size)
170     {
171       size_t unused = MEMSUB (dest->data, dest->allocd);
172       if (dest->max_length - unused <= new_size)
173         {
174           if (dest->length && dest->data)
175             memmove (dest->allocd, dest->data, dest->length);
176           dest->data = dest->allocd;
177         }
178
179       return 0;
180     }
181   else
182     {
183       size_t unused = MEMSUB (dest->data, dest->allocd);
184       size_t alloc_len =
185         MAX (new_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK);
186
187       dest->allocd = gnutls_realloc (dest->allocd, alloc_len);
188       if (dest->allocd == NULL)
189         {
190           gnutls_assert ();
191           return GNUTLS_E_MEMORY_ERROR;
192         }
193       dest->max_length = alloc_len;
194       dest->data = dest->allocd + unused;
195
196       if (dest->length && dest->data)
197         memmove (dest->allocd, dest->data, dest->length);
198       dest->data = dest->allocd;
199
200       return 0;
201     }
202 }
203
204 int
205 _gnutls_buffer_append_str (gnutls_buffer_st * dest, const char *src)
206 {
207   return _gnutls_buffer_append_data (dest, src, strlen (src));
208 }
209
210 /* returns data from a string in a constant buffer.
211  * The data will NOT be valid if buffer is released or
212  * data are appended in the buffer.
213  */
214 void
215 _gnutls_buffer_pop_datum (gnutls_buffer_st * str, gnutls_datum_t * data,
216                           size_t req_size)
217 {
218
219   if (str->length == 0)
220     {
221       data->data = NULL;
222       data->size = 0;
223       return;
224     }
225
226   if (req_size > str->length)
227     req_size = str->length;
228
229   data->data = str->data;
230   data->size = req_size;
231
232   str->data += req_size;
233   str->length -= req_size;
234
235   /* if string becomes empty start from begining */
236   if (str->length == 0)
237     {
238       str->data = str->allocd;
239     }
240
241   return;
242 }
243
244 /* converts the buffer to a datum if possible. After this call the buffer
245  * is at an usable state and might not be used or deinitialized */
246 int
247 _gnutls_buffer_to_datum (gnutls_buffer_st * str, gnutls_datum_t * data)
248 {
249
250   if (str->length == 0)
251     {
252       data->data = NULL;
253       data->size = 0;
254       return 0;
255     }
256
257   if (str->allocd != str->data)
258     {
259       data->data = gnutls_malloc (str->length);
260       if (data->data == NULL)
261         {
262           gnutls_assert ();
263           return GNUTLS_E_MEMORY_ERROR;
264         }
265       memcpy (data->data, str->data, str->length);
266       data->size = str->length;
267       _gnutls_buffer_clear (str);
268     }
269   else
270     {
271       data->data = str->data;
272       data->size = str->length;
273     }
274
275   return 0;
276 }
277
278 /* returns data from a string in a constant buffer.
279  */
280 void
281 _gnutls_buffer_pop_data (gnutls_buffer_st * str, void *data,
282                          size_t * req_size)
283 {
284   gnutls_datum_t tdata;
285
286   _gnutls_buffer_pop_datum (str, &tdata, *req_size);
287
288   *req_size = tdata.size;
289   memcpy (data, tdata.data, tdata.size);
290
291   return;
292 }
293
294 int
295 _gnutls_buffer_append_printf (gnutls_buffer_st * dest, const char *fmt, ...)
296 {
297   va_list args;
298   int len;
299   char *str;
300
301   va_start (args, fmt);
302   len = vasprintf (&str, fmt, args);
303   va_end (args);
304
305   if (len < 0 || !str)
306     return -1;
307
308   len = _gnutls_buffer_append_str (dest, str);
309
310   free (str);
311
312   return len;
313 }
314
315 static int
316 _gnutls_buffer_insert_data (gnutls_buffer_st * dest, int pos, const void *str,
317                             size_t str_size)
318 {
319   size_t orig_length = dest->length;
320   int ret;
321
322   ret = _gnutls_buffer_resize (dest, dest->length + str_size);  /* resize to make space */
323   if (ret < 0)
324     return ret;
325
326   memmove (&dest->data[pos + str_size], &dest->data[pos], orig_length - pos);
327
328   memcpy (&dest->data[pos], str, str_size);
329   dest->length += str_size;
330
331   return 0;
332 }
333
334 static void
335 _gnutls_buffer_delete_data (gnutls_buffer_st * dest, int pos, size_t str_size)
336 {
337   memmove (&dest->data[pos], &dest->data[pos + str_size],
338            dest->length - pos - str_size);
339
340   dest->length -= str_size;
341
342   return;
343 }
344
345
346 int
347 _gnutls_buffer_escape (gnutls_buffer_st * dest, int all,
348                        const char *const invalid_chars)
349 {
350   int rv = -1;
351   char t[5];
352   int pos = 0;
353
354   while (pos < dest->length)
355     {
356
357       if (all != 0 || (dest->data[pos] == '\\' || strchr (invalid_chars, dest->data[pos])
358           || !c_isgraph (dest->data[pos])))
359         {
360
361           snprintf (t, sizeof (t), "%%%.2X", (unsigned int) dest->data[pos]);
362
363           _gnutls_buffer_delete_data (dest, pos, 1);
364
365           if (_gnutls_buffer_insert_data (dest, pos, t, 3) < 0)
366             {
367               rv = -1;
368               goto cleanup;
369             }
370           pos+=3;
371         }
372       else
373         pos++;
374     }
375
376   rv = 0;
377
378 cleanup:
379
380   return rv;
381 }
382
383 int
384 _gnutls_buffer_unescape (gnutls_buffer_st * dest)
385 {
386   int rv = -1;
387   int pos = 0;
388
389   while (pos < dest->length)
390     {
391       if (dest->data[pos] == '%')
392         {
393           char b[3];
394           unsigned int u;
395           unsigned char x;
396
397           b[0] = dest->data[pos + 1];
398           b[1] = dest->data[pos + 2];
399           b[2] = 0;
400
401           sscanf (b, "%02x", &u);
402
403           x = u;
404
405           _gnutls_buffer_delete_data (dest, pos, 3);
406           _gnutls_buffer_insert_data (dest, pos, &x, 1);
407         }
408       pos++;
409     }
410
411   rv = 0;
412
413   return rv;
414 }
415
416
417 /* Converts the given string (old) to hex. A buffer must be provided
418  * to hold the new hex string. The new string will be null terminated.
419  * If the buffer does not have enough space to hold the string, a
420  * truncated hex string is returned (always null terminated).
421  */
422 char *
423 _gnutls_bin2hex (const void *_old, size_t oldlen,
424                  char *buffer, size_t buffer_size, const char *separator)
425 {
426   unsigned int i, j;
427   const opaque *old = _old;
428   int step = 2;
429   const char empty[] = "";
430
431   if (separator != NULL && separator[0] != 0)
432     step = 3;
433   else
434     separator = empty;
435
436   if (buffer_size < 3)
437     {
438       gnutls_assert();
439       return NULL;
440     }
441
442   i = j = 0;
443   sprintf (&buffer[j], "%.2x", old[i]);
444   j += 2;
445   i++;
446
447   for (; i < oldlen && j + step < buffer_size; j += step)
448     {
449       sprintf (&buffer[j], "%s%.2x", separator, old[i]);
450       i++;
451     }
452   buffer[j] = '\0';
453
454   return buffer;
455 }
456
457 /**
458  * gnutls_hex2bin:
459  * @hex_data: string with data in hex format
460  * @hex_size: size of hex data
461  * @bin_data: output array with binary data
462  * @bin_size: when calling *@bin_size should hold size of @bin_data,
463  *            on return will hold actual size of @bin_data.
464  *
465  * Convert a buffer with hex data to binary data.
466  *
467  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
468  *
469  * Since: 2.4.0
470  **/
471 int
472 gnutls_hex2bin (const char *hex_data,
473                 size_t hex_size, char *bin_data, size_t * bin_size)
474 {
475   return _gnutls_hex2bin (hex_data, (int) hex_size, bin_data, bin_size);
476 }
477
478 int
479 _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data,
480                  size_t * bin_size)
481 {
482   int i, j;
483   opaque hex2_data[3];
484   unsigned long val;
485
486   hex2_data[2] = 0;
487
488   for (i = j = 0; i < hex_size;)
489     {
490       if (!isxdigit (hex_data[i]))      /* skip non-hex such as the ':' in 00:FF */
491         {
492           i++;
493           continue;
494         }
495
496       if (j > *bin_size)
497         {
498           gnutls_assert ();
499           return GNUTLS_E_SHORT_MEMORY_BUFFER;
500         }
501
502       hex2_data[0] = hex_data[i];
503       hex2_data[1] = hex_data[i + 1];
504       i += 2;
505
506       val = strtoul ((char *) hex2_data, NULL, 16);
507       if (val == ULONG_MAX)
508         {
509           gnutls_assert ();
510           return GNUTLS_E_PARSING_ERROR;
511         }
512       bin_data[j] = val;
513       j++;
514     }
515   *bin_size = j;
516
517   return 0;
518 }
519
520
521 /* compare hostname against certificate, taking account of wildcards
522  * return 1 on success or 0 on error
523  *
524  * note: certnamesize is required as X509 certs can contain embedded NULs in
525  * the strings such as CN or subjectAltName.
526  *
527  * @level: is used for recursion. Use 0 when you call this function.
528  */
529 int
530 _gnutls_hostname_compare (const char *certname,
531                           size_t certnamesize, const char *hostname, int level)
532 {
533
534   if (level > 5)
535     return 0;
536
537   /* find the first different character */
538   for (; *certname && *hostname && c_toupper (*certname) == c_toupper (*hostname);
539        certname++, hostname++, certnamesize--)
540     ;
541
542   /* the strings are the same */
543   if (certnamesize == 0 && *hostname == '\0')
544     return 1;
545
546   if (*certname == '*')
547     {
548       /* a wildcard certificate */
549
550       certname++;
551       certnamesize--;
552
553       while (1)
554         {
555           /* Use a recursive call to allow multiple wildcards */
556           if (_gnutls_hostname_compare (certname, certnamesize, hostname, level+1))
557             return 1;
558
559           /* wildcards are only allowed to match a single domain
560              component or component fragment */
561           if (*hostname == '\0' || *hostname == '.')
562             break;
563           hostname++;
564         }
565
566       return 0;
567     }
568
569   return 0;
570 }
571
572 int
573 _gnutls_buffer_append_prefix (gnutls_buffer_st * buf, size_t data_size)
574 {
575   opaque ss[4];
576   _gnutls_write_uint32 (data_size, ss);
577   return _gnutls_buffer_append_data (buf, ss, 4);
578 }
579
580 /* Reads an uint32 number from the buffer. If check is non zero it will also check whether
581  * the number read, is less than the data in the buffer
582  */
583 int
584 _gnutls_buffer_pop_prefix (gnutls_buffer_st * buf, size_t * data_size,
585                            int check)
586 {
587   size_t size;
588
589   if (buf->length < 4)
590     {
591       gnutls_assert ();
592       return GNUTLS_E_PARSING_ERROR;
593     }
594
595   size = _gnutls_read_uint32 (buf->data);
596   if (check && size > buf->length - 4)
597     {
598       gnutls_assert ();
599       return GNUTLS_E_PARSING_ERROR;
600     }
601
602   buf->data += 4;
603   buf->length -= 4;
604
605   *data_size = size;
606
607   return 0;
608 }
609
610 int
611 _gnutls_buffer_pop_datum_prefix (gnutls_buffer_st * buf,
612                                  gnutls_datum_t * data)
613 {
614   size_t size;
615   int ret;
616
617   ret = _gnutls_buffer_pop_prefix (buf, &size, 1);
618   if (ret < 0)
619     {
620       gnutls_assert ();
621       return ret;
622     }
623
624   if (size > 0)
625     {
626       size_t osize = size;
627       _gnutls_buffer_pop_datum (buf, data, size);
628       if (osize != data->size)
629         {
630           gnutls_assert ();
631           return GNUTLS_E_PARSING_ERROR;
632         }
633     }
634   else
635     {
636       data->size = 0;
637       data->data = NULL;
638     }
639
640   return 0;
641 }
642
643 int
644 _gnutls_buffer_append_data_prefix (gnutls_buffer_st * buf, const void *data,
645                                    size_t data_size)
646 {
647   _gnutls_buffer_append_prefix (buf, data_size);
648   if (data_size > 0)
649     return _gnutls_buffer_append_data (buf, data, data_size);
650
651   return 0;
652 }
653
654 int
655 _gnutls_buffer_pop_data_prefix (gnutls_buffer_st * buf, void *data,
656                                 size_t * data_size)
657 {
658   size_t size;
659   int ret;
660
661   ret = _gnutls_buffer_pop_prefix (buf, &size, 1);
662   if (ret < 0)
663     {
664       gnutls_assert ();
665       return ret;
666     }
667
668   if (size > 0)
669     _gnutls_buffer_pop_data (buf, data, data_size);
670
671   return 0;
672 }