/* * Copyright (C) 2002, 2004, 2005, 2007, 2008 Free Software Foundation * * Author: Nikos Mavrogiannopoulos * * This file is part of GNUTLS. * * The GNUTLS library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA * */ #include #include #include #include #include /* These function are like strcat, strcpy. They only * do bound checking (they shouldn't cause buffer overruns), * and they always produce null terminated strings. * * They should be used only with null terminated strings. */ void _gnutls_str_cat (char *dest, size_t dest_tot_size, const char *src) { size_t str_size = strlen (src); size_t dest_size = strlen (dest); if (dest_tot_size - dest_size > str_size) { strcat (dest, src); } else { if (dest_tot_size - dest_size > 0) { strncat (dest, src, (dest_tot_size - dest_size) - 1); dest[dest_tot_size - 1] = 0; } } } void _gnutls_str_cpy (char *dest, size_t dest_tot_size, const char *src) { size_t str_size = strlen (src); if (dest_tot_size > str_size) { strcpy (dest, src); } else { if (dest_tot_size > 0) { strncpy (dest, src, (dest_tot_size) - 1); dest[dest_tot_size - 1] = 0; } } } void _gnutls_mem_cpy (char *dest, size_t dest_tot_size, const char *src, size_t src_size) { if (dest_tot_size >= src_size) { memcpy (dest, src, src_size); } else { if (dest_tot_size > 0) { memcpy (dest, src, dest_tot_size); } } } void _gnutls_string_init (gnutls_string * str, gnutls_alloc_function alloc_func, gnutls_realloc_function realloc_func, gnutls_free_function free_func) { str->data = str->allocd = NULL; str->max_length = 0; str->length = 0; str->alloc_func = alloc_func; str->free_func = free_func; str->realloc_func = realloc_func; } void _gnutls_string_clear (gnutls_string * str) { if (str == NULL || str->allocd == NULL) return; str->free_func (str->allocd); str->data = str->allocd = NULL; str->max_length = 0; str->length = 0; } #define MIN_CHUNK 256 int _gnutls_string_append_data (gnutls_string * dest, const void *data, size_t data_size) { size_t tot_len = data_size + dest->length; if (dest->max_length >= tot_len) { size_t unused = MEMSUB(dest->data, dest->allocd); if (dest->max_length - unused <= tot_len) { if (dest->length && dest->data) memmove(dest->allocd, dest->data, dest->length); dest->data = dest->allocd; } memcpy (&dest->data[dest->length], data, data_size); dest->length = tot_len; return tot_len; } else { size_t unused = MEMSUB(dest->data, dest->allocd); size_t new_len = MAX (data_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK); dest->allocd = dest->realloc_func (dest->allocd, new_len); if (dest->allocd == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } dest->max_length = new_len; dest->data = dest->allocd + unused; if (dest->length && dest->data) memmove(dest->allocd, dest->data, dest->length); dest->data = dest->allocd; memcpy (&dest->data[dest->length], data, data_size); dest->length = tot_len; return tot_len; } } int _gnutls_string_resize (gnutls_string * dest, size_t new_size) { if (dest->max_length >= new_size) { size_t unused = MEMSUB(dest->data, dest->allocd); if (dest->max_length - unused <= new_size) { if (dest->length && dest->data) memmove(dest->allocd, dest->data, dest->length); dest->data = dest->allocd; } return 0; } else { size_t unused = MEMSUB(dest->data, dest->allocd); size_t alloc_len = MAX (new_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK); dest->allocd = dest->realloc_func (dest->allocd, alloc_len); if (dest->allocd == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } dest->max_length = alloc_len; dest->data = dest->allocd + unused; if (dest->length && dest->data) memmove(dest->allocd, dest->data, dest->length); dest->data = dest->allocd; return 0; } } int _gnutls_string_append_str (gnutls_string * dest, const char *src) { return _gnutls_string_append_data (dest, src, strlen(src)); } /* returns data from a string in a constant buffer. * The data will NOT be valid if buffer is released or * data are appended in the buffer. */ void _gnutls_string_get_datum (gnutls_string * str, gnutls_datum *data, size_t req_size) { if (str->length == 0) { data->data = NULL; data->size = 0; return; } if (req_size > str->length) req_size = str->length; data->data = str->data; data->size = req_size; str->data += req_size; str->length -= req_size; /* if string becomes empty start from begining */ if (str->length == 0) { str->data = str->allocd; } return; } /* returns data from a string in a constant buffer. */ void _gnutls_string_get_data (gnutls_string * str, void *data, size_t *req_size) { gnutls_datum tdata; _gnutls_string_get_datum( str, &tdata, *req_size); *req_size = tdata.size; memcpy( data, tdata.data, tdata.size); return; } int _gnutls_string_append_printf (gnutls_string * dest, const char *fmt, ...) { va_list args; int len; char *str; va_start (args, fmt); len = vasprintf (&str, fmt, args); va_end (args); if (len < 0 || !str) return -1; len = _gnutls_string_append_str (dest, str); free (str); return len; } /* Converts the given string (old) to hex. A buffer must be provided * to hold the new hex string. The new string will be null terminated. * If the buffer does not have enough space to hold the string, a * truncated hex string is returned (always null terminated). */ char * _gnutls_bin2hex (const void *_old, size_t oldlen, char *buffer, size_t buffer_size) { unsigned int i, j; const opaque *old = _old; for (i = j = 0; i < oldlen && j + 2 < buffer_size; j += 2) { sprintf (&buffer[j], "%.2x", old[i]); i++; } buffer[j] = '\0'; return buffer; } /** * gnutls_hex2bin - convert hex string into binary buffer. * @hex_data: string with data in hex format * @hex_size: size of hex data * @bin_data: output array with binary data * @bin_size: when calling *@bin_size should hold size of @bin_data, * on return will hold actual size of @bin_data. * * Convert a buffer with hex data to binary data. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error. * * Since: 2.4.0 **/ int gnutls_hex2bin (const char *hex_data, size_t hex_size, char *bin_data, size_t * bin_size) { return _gnutls_hex2bin (hex_data, (int) hex_size, bin_data, bin_size); } int _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data, size_t * bin_size) { int i, j; opaque hex2_data[3]; unsigned long val; /* FIXME: we don't handle whitespace. */ hex_size /= 2; if (*bin_size < (size_t) hex_size) { gnutls_assert (); return GNUTLS_E_SHORT_MEMORY_BUFFER; } for (i = j = 0; j < hex_size; i += 2, j++) { hex2_data[0] = hex_data[i]; hex2_data[1] = hex_data[i + 1]; hex2_data[2] = 0; val = strtoul ((char *) hex2_data, NULL, 16); if (val == ULONG_MAX) { gnutls_assert (); return GNUTLS_E_SRP_PWD_PARSING_ERROR; } bin_data[j] = val; } return 0; } /* compare hostname against certificate, taking account of wildcards * return 1 on success or 0 on error */ int _gnutls_hostname_compare (const char *certname, const char *hostname) { /* find the first different character */ for (; *certname && *hostname && toupper (*certname) == toupper (*hostname); certname++, hostname++) ; /* the strings are the same */ if (strlen (certname) == 0 && strlen (hostname) == 0) return 1; if (*certname == '*') { /* a wildcard certificate */ certname++; while (1) { /* Use a recursive call to allow multiple wildcards */ if (_gnutls_hostname_compare (certname, hostname)) { return 1; } /* wildcards are only allowed to match a single domain component or component fragment */ if (*hostname == '\0' || *hostname == '.') break; hostname++; } return 0; } return 0; }