summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2012-11-20 19:16:44 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2012-11-20 19:16:50 +0100
commit77727d5612698cbc919cb1f1c359931a30819c93 (patch)
treeaaef506b263cf523e76be547781b922ef4b9f218
parent517699a4c19ac33ea6e064e136e692fa6add1dcf (diff)
downloadgnutls-77727d5612698cbc919cb1f1c359931a30819c93.tar.gz
improved iconv support.
-rw-r--r--NEWS2
-rw-r--r--lib/system.c40
2 files changed, 35 insertions, 7 deletions
diff --git a/NEWS b/NEWS
index 367e94823b..e516d04ddc 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,7 @@ See the end for copying conditions.
extension.
** libgnutls: Handle BMPString (UCS-2) encoding in the Distinguished
-Name by translating it to UTF-8 (works on windows or systems with libiconv).
+Name by translating it to UTF-8 (works on windows or systems with iconv).
** libgnutls: Added PKCS #11 key generation function that returns the
public key on generation.
diff --git a/lib/system.c b/lib/system.c
index dcca1450c1..899598dbd4 100644
--- a/lib/system.c
+++ b/lib/system.c
@@ -477,13 +477,15 @@ gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
# include <iconv.h>
+#define INC(x) (2*x)
+
int _gnutls_ucs2_to_utf8(const void* data, size_t size, gnutls_datum_t *output)
{
iconv_t conv;
int ret;
-size_t orig, dstlen = size*2;
+size_t orig, dstlen = INC(size), tmp;
char* src = (void*)data;
-char* dst, *pdst;
+char* dst = NULL, *pdst;
if (size == 0)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
@@ -496,23 +498,49 @@ char* dst, *pdst;
if (dst == NULL)
{
ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
- goto cleanup;
+ goto fail;
}
orig = dstlen;
ret = iconv(conv, &src, &size, &pdst, &dstlen);
if (ret == -1)
{
- ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
- goto cleanup;
+ if (dstlen != 0 || size == 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+ goto fail;
+ }
+
+ /* otherwise the buffer wasn't sufficient */
+ tmp = orig + INC(orig);
+ dstlen += INC(orig);
+
+ dst = gnutls_realloc_fast(dst, tmp);
+ if (dst == NULL)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto fail;
+ }
+ pdst = dst + orig;
+ orig = tmp;
+
+ ret = iconv(conv, &src, &size, &pdst, &dstlen);
+ if (ret == -1)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+ goto fail;
+ }
}
-
output->data = (void*)dst;
output->size = orig-dstlen;
output->data[output->size] = 0;
ret = 0;
+ goto cleanup;
+
+fail:
+ gnutls_free(dst);
cleanup:
iconv_close(conv);