2 * Copyright (C) 2002, 2004, 2005, 2007, 2008, 2009, 2010 Free Software
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,
26 #include <gnutls_int.h>
27 #include <gnutls_errors.h>
28 #include <gnutls_num.h>
29 #include <gnutls_str.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.
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
)
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;
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
)
69 if (dest_tot_size
> 0)
71 strncpy (dest
, src
, (dest_tot_size
) - 1);
72 dest
[dest_tot_size
- 1] = 0;
78 _gnutls_mem_cpy (char *dest
, size_t dest_tot_size
, const char *src
,
82 if (dest_tot_size
>= src_size
)
84 memcpy (dest
, src
, src_size
);
88 if (dest_tot_size
> 0)
90 memcpy (dest
, src
, dest_tot_size
);
96 _gnutls_buffer_init (gnutls_buffer_st
* str
)
98 str
->data
= str
->allocd
= NULL
;
104 _gnutls_buffer_clear (gnutls_buffer_st
* str
)
106 if (str
== NULL
|| str
->allocd
== NULL
)
108 gnutls_free (str
->allocd
);
110 str
->data
= str
->allocd
= NULL
;
115 #define MIN_CHUNK 1024
118 _gnutls_buffer_append_data (gnutls_buffer_st
* dest
, const void *data
,
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
;
141 size_t unused
= MEMSUB (dest
->data
, dest
->allocd
);
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
)
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
;
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
;
182 size_t unused
= MEMSUB (dest
->data
, dest
->allocd
);
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
)
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
;
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.
214 _gnutls_buffer_pop_datum (gnutls_buffer_st
* str
, gnutls_datum_t
* data
,
218 if (str
->length
== 0)
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
;
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)
256 if (str
->allocd
!= str
->data
)
258 data
->data
= gnutls_malloc (str
->length
);
259 if (data
->data
== NULL
)
262 return GNUTLS_E_MEMORY_ERROR
;
264 memcpy (data
->data
, str
->data
, str
->length
);
265 data
->size
= str
->length
;
266 _gnutls_buffer_clear (str
);
270 data
->data
= str
->data
;
271 data
->size
= str
->length
;
277 /* returns data from a string in a constant buffer.
280 _gnutls_buffer_pop_data (gnutls_buffer_st
* str
, void *data
,
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
);
294 _gnutls_buffer_append_printf (gnutls_buffer_st
* dest
, const char *fmt
, ...)
300 va_start (args
, fmt
);
301 len
= vasprintf (&str
, fmt
, args
);
307 len
= _gnutls_buffer_append_str (dest
, str
);
315 _gnutls_buffer_insert_data (gnutls_buffer_st
* dest
, int pos
, const void *str
,
318 size_t orig_length
= dest
->length
;
321 ret
= _gnutls_buffer_resize (dest
, dest
->length
+ str_size
); /* resize to make space */
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
;
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
;
346 _gnutls_buffer_escape (gnutls_buffer_st
* dest
,
347 const char *const invalid_chars
)
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)
382 _gnutls_buffer_unescape (gnutls_buffer_st
* dest
)
387 while (pos
< dest
->length
)
389 if (dest
->data
[pos
] == '%')
395 b
[0] = dest
->data
[pos
+ 1];
396 b
[1] = dest
->data
[pos
+ 2];
399 sscanf (b
, "%02x", &u
);
403 _gnutls_buffer_delete_data (dest
, pos
, 3);
404 _gnutls_buffer_insert_data (dest
, pos
, &x
, 1);
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).
421 _gnutls_bin2hex (const void *_old
, size_t oldlen
,
422 char *buffer
, size_t buffer_size
, const char *separator
)
425 const opaque
*old
= _old
;
427 const char empty
[] = "";
429 if (separator
!= NULL
&& separator
[0] != 0)
441 sprintf (&buffer
[j
], "%.2x", old
[i
]);
445 for (; i
< oldlen
&& j
+ step
< buffer_size
; j
+= step
)
447 sprintf (&buffer
[j
], "%s%.2x", separator
, old
[i
]);
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.
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
,
486 for (i
= j
= 0; i
< hex_size
;)
488 if (!isxdigit (hex_data
[i
])) /* skip non-hex such as the ':' in 00:FF */
497 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
500 hex2_data
[0] = hex_data
[i
];
501 hex2_data
[1] = hex_data
[i
+ 1];
504 val
= strtoul ((char *) hex2_data
, NULL
, 16);
505 if (val
== ULONG_MAX
)
508 return GNUTLS_E_PARSING_ERROR
;
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')
538 if (*certname
== '*')
540 /* a wildcard certificate */
547 /* Use a recursive call to allow multiple wildcards */
548 if (_gnutls_hostname_compare (certname
, certnamesize
, hostname
))
551 /* wildcards are only allowed to match a single domain
552 component or component fragment */
553 if (*hostname
== '\0' || *hostname
== '.')
565 _gnutls_buffer_append_prefix (gnutls_buffer_st
* buf
, size_t data_size
)
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
,
584 return GNUTLS_E_PARSING_ERROR
;
587 size
= _gnutls_read_uint32 (buf
->data
);
588 if (check
&& size
> buf
->length
- 4)
591 return GNUTLS_E_PARSING_ERROR
;
603 _gnutls_buffer_pop_datum_prefix (gnutls_buffer_st
* buf
,
604 gnutls_datum_t
* data
)
609 ret
= _gnutls_buffer_pop_prefix (buf
, &size
, 1);
619 _gnutls_buffer_pop_datum (buf
, data
, size
);
620 if (osize
!= data
->size
)
623 return GNUTLS_E_PARSING_ERROR
;
636 _gnutls_buffer_append_data_prefix (gnutls_buffer_st
* buf
, const void *data
,
639 _gnutls_buffer_append_prefix (buf
, data_size
);
641 return _gnutls_buffer_append_data (buf
, data
, data_size
);
647 _gnutls_buffer_pop_data_prefix (gnutls_buffer_st
* buf
, void *data
,
653 ret
= _gnutls_buffer_pop_prefix (buf
, &size
, 1);
661 _gnutls_buffer_pop_data (buf
, data
, data_size
);