From 2e97c2796581c27213962c77f5a8571a598f9a2e Mon Sep 17 00:00:00 2001
From: Simon Josefsson <simon@josefsson.org>
Date: Wed, 8 Jul 2015 02:06:22 +0200
Subject: [PATCH] libidn: stringprep_utf8_to_ucs4 now rejects invalid UTF-8.
 CVE-2015-2059

---
 .gitignore                         |    8 ++
 NEWS                               |   31 +++++-
 lib/gl/Makefile.am                 |   10 +-
 lib/gl/m4/gnulib-cache.m4          |    3 +-
 lib/gl/m4/gnulib-comp.m4           |    5 +
 lib/gl/unistr/u8-check.c           |  105 ++++++++++++++++++++
 lib/gltests/Makefile.am            |   10 ++
 lib/gltests/unistr/test-u8-check.c |  188 ++++++++++++++++++++++++++++++++++++
 lib/nfkc.c                         |   19 +++-
 lib/strerror-idna.c                |    2 +-
 lib/strerror-stringprep.c          |    4 +
 lib/stringprep.c                   |    5 +-
 lib/stringprep.h                   |    1 +
 tests/Makefile.am                  |    2 +-
 tests/tst_badutf8.c                |   50 ++++++++++
 tests/tst_stringprep.c             |   22 +++--
 16 files changed, 450 insertions(+), 15 deletions(-)
 create mode 100644 lib/gl/unistr/u8-check.c
 create mode 100644 lib/gltests/unistr/test-u8-check.c
 create mode 100644 tests/tst_badutf8.c

Index: libidn-1.10/lib/gl/unistr/u8-check.c
===================================================================
--- /dev/null
+++ libidn-1.10/lib/gl/unistr/u8-check.c
@@ -0,0 +1,105 @@
+/* Check UTF-8 string.
+   Copyright (C) 2002, 2006-2007, 2009-2015 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2002.
+
+   This program 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 program 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 program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "unistr.h"
+
+const uint8_t *
+u8_check (const uint8_t *s, size_t n)
+{
+  const uint8_t *s_end = s + n;
+
+  while (s < s_end)
+    {
+      /* Keep in sync with unistr.h and u8-mbtouc-aux.c.  */
+      uint8_t c = *s;
+
+      if (c < 0x80)
+        {
+          s++;
+          continue;
+        }
+      if (c >= 0xc2)
+        {
+          if (c < 0xe0)
+            {
+              if (s + 2 <= s_end
+                  && (s[1] ^ 0x80) < 0x40)
+                {
+                  s += 2;
+                  continue;
+                }
+            }
+          else if (c < 0xf0)
+            {
+              if (s + 3 <= s_end
+                  && (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
+                  && (c >= 0xe1 || s[1] >= 0xa0)
+                  && (c != 0xed || s[1] < 0xa0))
+                {
+                  s += 3;
+                  continue;
+                }
+            }
+          else if (c < 0xf8)
+            {
+              if (s + 4 <= s_end
+                  && (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
+                  && (s[3] ^ 0x80) < 0x40
+                  && (c >= 0xf1 || s[1] >= 0x90)
+#if 1
+                  && (c < 0xf4 || (c == 0xf4 && s[1] < 0x90))
+#endif
+                 )
+                {
+                  s += 4;
+                  continue;
+                }
+            }
+#if 0
+          else if (c < 0xfc)
+            {
+              if (s + 5 <= s_end
+                  && (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
+                  && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
+                  && (c >= 0xf9 || s[1] >= 0x88))
+                {
+                  s += 5;
+                  continue;
+                }
+            }
+          else if (c < 0xfe)
+            {
+              if (s + 6 <= s_end
+                  && (s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
+                  && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
+                  && (s[5] ^ 0x80) < 0x40
+                  && (c >= 0xfd || s[1] >= 0x84))
+                {
+                  s += 6;
+                  continue;
+                }
+            }
+#endif
+        }
+      /* invalid or incomplete multibyte character */
+      return s;
+    }
+  return NULL;
+}
Index: libidn-1.10/lib/gltests/unistr/test-u8-check.c
===================================================================
--- /dev/null
+++ libidn-1.10/lib/gltests/unistr/test-u8-check.c
@@ -0,0 +1,188 @@
+/* Test of u8_check() function.
+   Copyright (C) 2010-2015 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2010.  */
+
+#include <config.h>
+
+#include "unistr.h"
+
+#include "macros.h"
+
+int
+main ()
+{
+  /* Test empty string.  */
+  {
+    static const uint8_t input[] = "";
+    ASSERT (u8_check (input, 0) == NULL);
+  }
+
+  /* Test valid non-empty string.  */
+  {
+    static const uint8_t input[] = /* "ÐÐ°Ð½Ð¸Ð»Ð¾ Ð¨ÐµÐ³Ð°Ð½" */
+      "\320\224\320\260\320\275\320\270\320\273\320\276 \320\250\320\265\320\263\320\260\320\275";
+    ASSERT (u8_check (input, sizeof (input) - 1) == NULL);
+  }
+
+  /* Test out-of-range character with 4 bytes: U+110000.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\364\220\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test out-of-range character with 5 bytes: U+200000.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\370\210\200\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test out-of-range character with 6 bytes: U+4000000.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\374\204\200\200\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test invalid lead byte.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\376\200\200\200\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\377\200\200\200\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test overlong 2-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\301\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test overlong 3-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\340\200\277";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test overlong 4-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\360\200\277\277";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test invalid bytes in 2-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\302\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == NULL);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\302\100";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\302\300";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test invalid bytes in 3-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\342\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == NULL);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\342\100\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\342\300\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\342\200\100";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\342\200\300";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test invalid bytes in 4-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\200\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == NULL);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\100\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\300\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\200\100\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\200\300\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\200\200\100";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\200\200\300";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test truncated/incomplete 2-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\302";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test truncated/incomplete 3-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\342\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test truncated/incomplete 4-byte character.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\362\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test missing lead byte.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\200\200\200\200\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  /* Test surrogate codepoints.  */
+  {
+    static const uint8_t input[] = "\320\224\320\260\355\240\200\355\260\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+  {
+    static const uint8_t input[] = "\320\224\320\260\355\260\200";
+    ASSERT (u8_check (input, sizeof (input) - 1) == input + 4);
+  }
+
+  return 0;
+}
Index: libidn-1.10/lib/nfkc.c
===================================================================
--- libidn-1.10.orig/lib/nfkc.c
+++ libidn-1.10/lib/nfkc.c
@@ -25,6 +25,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include "unistr.h"
 
 #include "stringprep.h"
 
@@ -966,9 +967,10 @@ stringprep_unichar_to_utf8 (uint32_t c,
  * @items_written: location to store the number of characters in the
  *                 result, or %NULL.
  *
- * Convert a string from UTF-8 to a 32-bit fixed width
- * representation as UCS-4, assuming valid UTF-8 input.
- * This function does no error checking on the input.
+ * Convert a string from UTF-8 to a 32-bit fixed width representation
+ * as UCS-4.  The function now performs error checking to verify that
+ * the input is valid UTF-8 (before it was documented to not do error
+ * checking).
  *
  * Return value: a pointer to a newly allocated UCS-4 string.
  *               This value must be freed with free().
@@ -976,6 +978,16 @@ stringprep_unichar_to_utf8 (uint32_t c,
 uint32_t *
 stringprep_utf8_to_ucs4 (const char *str, ssize_t len, size_t * items_written)
 {
+  size_t n;
+
+  if (len < 0)
+    n = strlen (str);
+  else
+    n = len;
+
+  if (u8_check ((const uint8_t *) str, n))
+    return NULL;
+
   return g_utf8_to_ucs4_fast (str, (glong) len, (glong *) items_written);
 }
 
@@ -1005,6 +1017,8 @@ stringprep_ucs4_to_utf8 (const uint32_t
 			 (glong *) items_written, NULL);
 }
 
+#include <unistr.h>
+
 /**
  * stringprep_utf8_nfkc_normalize - normalize Unicode string
  * @str: a UTF-8 encoded string.
Index: libidn-1.10/lib/strerror-idna.c
===================================================================
--- libidn-1.10.orig/lib/strerror-idna.c
+++ libidn-1.10/lib/strerror-idna.c
@@ -107,7 +107,7 @@ idna_strerror (Idna_rc rc)
       break;
 
     case IDNA_ICONV_ERROR:
-      p = _("System iconv failed");
+      p = _("Could not convert string in locale encoding");
       break;
 
     case IDNA_MALLOC_ERROR:
Index: libidn-1.10/lib/strerror-stringprep.c
===================================================================
--- libidn-1.10.orig/lib/strerror-stringprep.c
+++ libidn-1.10/lib/strerror-stringprep.c
@@ -57,6 +57,7 @@
  *   This usually indicate a problem in the calling application.
  * STRINGPREP_UNKNOWN_PROFILE: The supplied profile name was not
  *   known to the library.
+ * STRINGPREP_ICONV_ERROR: Could not convert string in locale encoding.
  * STRINGPREP_NFKC_FAILED: The Unicode NFKC operation failed.  This
  *   usually indicate an internal error in the library.
  * STRINGPREP_MALLOC_ERROR: The malloc() was out of memory.  This is
@@ -113,6 +114,9 @@ stringprep_strerror (Stringprep_rc rc)
     case STRINGPREP_UNKNOWN_PROFILE:
       p = _("Unknown profile");
       break;
+    case STRINGPREP_ICONV_ERROR:
+      p = _("Could not convert string in locale encoding.");
+      break;
 
     case STRINGPREP_NFKC_FAILED:
       p = _("Unicode normalization failed (internal error)");
Index: libidn-1.10/lib/stringprep.c
===================================================================
--- libidn-1.10.orig/lib/stringprep.c
+++ libidn-1.10/lib/stringprep.c
@@ -373,6 +373,8 @@ stringprep (char *in,
       if (ucs4)
 	free (ucs4);
       ucs4 = stringprep_utf8_to_ucs4 (in, -1, &ucs4len);
+      if (ucs4 == NULL)
+	return STRINGPREP_ICONV_ERROR;
       maxucs4len = ucs4len + adducs4len;
       newp = realloc (ucs4, maxucs4len * sizeof (uint32_t));
       if (!newp)
@@ -395,7 +397,7 @@ stringprep (char *in,
   utf8 = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0);
   free (ucs4);
   if (!utf8)
-    return STRINGPREP_MALLOC_ERROR;
+    return STRINGPREP_ICONV_ERROR;
 
   if (strlen (utf8) >= maxlen)
     {
@@ -584,6 +586,7 @@ stringprep_profile (const char *in,
  *   This usually indicate a problem in the calling application.
  * @STRINGPREP_UNKNOWN_PROFILE: The supplied profile name was not
  *   known to the library.
+ * @STRINGPREP_ICONV_ERROR: Could not convert string in locale encoding.
  * @STRINGPREP_NFKC_FAILED: The Unicode NFKC operation failed.  This
  *   usually indicate an internal error in the library.
  * @STRINGPREP_MALLOC_ERROR: The malloc() was out of memory.  This is
Index: libidn-1.10/lib/stringprep.h
===================================================================
--- libidn-1.10.orig/lib/stringprep.h
+++ libidn-1.10/lib/stringprep.h
@@ -58,6 +58,7 @@ extern "C"
     STRINGPREP_PROFILE_ERROR = 101,
     STRINGPREP_FLAG_ERROR = 102,
     STRINGPREP_UNKNOWN_PROFILE = 103,
+    STRINGPREP_ICONV_ERROR = 104,
     /* Internal errors. */
     STRINGPREP_NFKC_FAILED = 200,
     STRINGPREP_MALLOC_ERROR = 201
Index: libidn-1.10/tests/Makefile.am
===================================================================
--- libidn-1.10.orig/tests/Makefile.am
+++ libidn-1.10/tests/Makefile.am
@@ -25,7 +25,7 @@ libutils_la_SOURCES = utils.h utils.c
 
 ctests = tst_stringprep$(EXEEXT) tst_punycode$(EXEEXT)		\
 	tst_idna$(EXEEXT) tst_idna2$(EXEEXT) tst_nfkc$(EXEEXT)	\
-	tst_pr29$(EXEEXT) tst_strerror$(EXEEXT)
+	tst_pr29$(EXEEXT) tst_strerror$(EXEEXT) tst_badutf8$(EXEEXT)
 if TLD
 ctests += tst_tld$(EXEEXT)
 endif
Index: libidn-1.10/tests/tst_badutf8.c
===================================================================
--- /dev/null
+++ libidn-1.10/tests/tst_badutf8.c
@@ -0,0 +1,50 @@
+/* tst_badutf8.c --- Self tests for malformed UTF-8 regressions.
+ * Copyright (C) 2015 Simon Josefsson
+ *
+ * This file is part of GNU Libidn.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <idna.h>
+#include <idn-free.h>
+
+#include "utils.h"
+
+void
+doit (void)
+{
+  char *badutf8 = strdup ("\x7e\x64\x61\x72\x10\x2f\x2f\xf9\x2b\x71"
+			  "\x60\x79\x7b\x2e\x63\x75\x2b\x61\x65\x72"
+			  "\x75\x65\x56\x66\x7f\x62\xc5\x76\xe5\x00");
+  char *s = NULL;
+  int rc;
+
+  rc = idna_to_ascii_8z (badutf8, &s, 0);
+  free (badutf8);
+  if (rc != IDNA_ICONV_ERROR)
+    fail ("rc %d\n", rc);
+
+  idn_free (s);
+}
Index: libidn-1.10/tests/tst_stringprep.c
===================================================================
--- libidn-1.10.orig/tests/tst_stringprep.c
+++ libidn-1.10/tests/tst_stringprep.c
@@ -100,7 +100,8 @@ const struct stringprep strprep[] = {
    "\xF4\x8F\xBF\xBF", NULL, "Nameprep", 0,
    STRINGPREP_CONTAINS_PROHIBITED},
   {"Surrogate code U+DF42",
-   "\xED\xBD\x82", NULL, "Nameprep", 0, STRINGPREP_CONTAINS_PROHIBITED},
+   "\xED\xBD\x82", NULL, "Nameprep", 0, STRINGPREP_ICONV_ERROR
+   /* was STRINGPREP_CONTAINS_PROHIBITED */},
   {"Non-plain text character U+FFFD",
    "\xEF\xBF\xBD", NULL, "Nameprep", 0, STRINGPREP_CONTAINS_PROHIBITED},
   {"Ideographic description character U+2FF5",
@@ -223,15 +224,22 @@ doit (void)
 	  hexprint (strprep[i].in, strlen (strprep[i].in));
 	  binprint (strprep[i].in, strlen (strprep[i].in));
 	}
-
       {
 	uint32_t *l;
-	char *x;
+	char *x = NULL;
 	l = stringprep_utf8_to_ucs4 (strprep[i].in, -1, NULL);
-	x = stringprep_ucs4_to_utf8 (l, -1, NULL, NULL);
+	if (l)
+	  x = stringprep_ucs4_to_utf8 (l, -1, NULL, NULL);
 	free (l);
-
-	if (strcmp (strprep[i].in, x) != 0)
+	if (i == 29)
+	  /* Ignoring known bad UTF-8 in entry 29 */
+	  continue;
+	else if (l == NULL)
+	  {
+	    fail ("bad UTF-8 in entry %ld\n", i);
+	    continue;
+	  }
+	else if (strcmp (strprep[i].in, x) != 0)
 	  {
 	    fail ("bad UTF-8 in entry %d\n", i);
 	    if (debug)
@@ -243,10 +251,12 @@ doit (void)
 		escapeprint (x, strlen (x));
 		hexprint (x, strlen (x));
 	      }
+	    continue;
 	  }
 
 	free (x);
       }
+
       rc = stringprep_profile (strprep[i].in, &p,
 			       strprep[i].profile ?
 			       strprep[i].profile :
Index: libidn-1.10/doc/Makefile.am
===================================================================
--- libidn-1.10.orig/doc/Makefile.am
+++ libidn-1.10/doc/Makefile.am
@@ -58,14 +58,7 @@ idn.1: $(top_srcdir)/src/idn.c $(top_src
 
 # GDOC
 
-GDOC_SRC = $(top_srcdir)/lib/idna.c $(top_srcdir)/lib/nfkc.c	\
-	$(top_srcdir)/lib/pr29.c $(top_srcdir)/lib/punycode.c	\
-	$(top_srcdir)/lib/stringprep.c $(top_srcdir)/lib/tld.c	\
-	$(top_srcdir)/lib/toutf8.c $(top_srcdir)/lib/version.c \
-	$(top_srcdir)/lib/strerror-idna.c $(top_srcdir)/lib/strerror-pr29.c \
-	$(top_srcdir)/lib/strerror-punycode.c \
-	$(top_srcdir)/lib/strerror-stringprep.c \
-	$(top_srcdir)/lib/strerror-tld.c
+GDOC_SRC =
 GDOC_TEXI_PREFIX = texi/
 GDOC_MAN_PREFIX = man/
 GDOC_MAN_EXTRA_ARGS = -module $(PACKAGE) -sourceversion $(VERSION) \
Index: libidn-1.10/lib/gl/Makefile.am
===================================================================
--- libidn-1.10.orig/lib/gl/Makefile.am
+++ libidn-1.10/lib/gl/Makefile.am
@@ -41,6 +41,40 @@ libgnu_la_SOURCES += c-ctype.h c-ctype.c
 
 ## end   gnulib module c-ctype
 
+## begin gnulib module unitypes
+
+BUILT_SOURCES += unitypes.h
+
+unitypes.h: unitypes.in.h
+	$(AM_V_GEN)rm -f $@-t $@ && \
+	{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+	  cat $(srcdir)/unitypes.in.h; \
+	} > $@-t && \
+	mv -f $@-t $@
+MOSTLYCLEANFILES += unitypes.h unitypes.h-t
+
+EXTRA_DIST += unitypes.in.h
+
+## end   gnulib module unitypes
+
+BUILT_SOURCES += unistr.h
+
+unistr.h: unistr.in.h
+	$(AM_V_GEN)rm -f $@-t $@ && \
+	{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+	  cat $(srcdir)/unistr.in.h; \
+	} > $@-t && \
+	mv -f $@-t $@
+MOSTLYCLEANFILES += unistr.h unistr.h-t
+
+EXTRA_DIST += unistr.in.h
+
+## begin gnulib module unistr/u8-check
+
+libgnu_la_SOURCES += unistr/u8-check.c
+
+## end   gnulib module unistr/u8-check
+
 ## begin gnulib module c-strcase
 
 libgnu_la_SOURCES += c-strcase.h c-strcasecmp.c c-strncasecmp.c
Index: libidn-1.10/lib/gltests/Makefile.am
===================================================================
--- libidn-1.10.orig/lib/gltests/Makefile.am
+++ libidn-1.10/lib/gltests/Makefile.am
@@ -140,6 +140,16 @@ EXTRA_DIST += test-unistd.c
 
 ## end   gnulib module unistd-tests
 
+## begin gnulib module unistr/u8-check-tests
+
+TESTS += test-u8-check
+check_PROGRAMS += test-u8-check
+test_u8_check_SOURCES = unistr/test-u8-check.c
+test_u8_check_LDADD = $(LDADD) $(LIBUNISTRING)
+EXTRA_DIST += unistr/test-u8-check.c macros.h
+
+## end   gnulib module unistr/u8-check-tests
+
 ## begin gnulib module verify
 
 libtests_a_SOURCES += verify.h
Index: libidn-1.10/lib/gl/m4/gnulib-comp.m4
===================================================================
--- libidn-1.10.orig/lib/gl/m4/gnulib-comp.m4
+++ libidn-1.10/lib/gl/m4/gnulib-comp.m4
@@ -222,6 +222,7 @@ AC_DEFUN([lgl_FILE_LIST], [
   lib/strverscmp.c
   lib/unistd.in.h
   lib/wchar.in.h
+  lib/unistr/u8-check.c
   m4/extensions.m4
   m4/gnulib-common.m4
   m4/iconv.m4
@@ -258,6 +259,7 @@ AC_DEFUN([lgl_FILE_LIST], [
   tests/test-strverscmp.c
   tests/test-unistd.c
   tests/test-wchar.c
+  tests/unistr/test-u8-check.c
   tests=lib/dummy.c
   tests=lib/intprops.h
   tests=lib/verify.h
Index: libidn-1.10/lib/gl/unistr.in.h
===================================================================
--- /dev/null
+++ libidn-1.10/lib/gl/unistr.in.h
@@ -0,0 +1,750 @@
+/* Elementary Unicode string functions.
+   Copyright (C) 2001-2002, 2005-2013 Free Software Foundation, Inc.
+
+   This program 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 program 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 program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _UNISTR_H
+#define _UNISTR_H
+
+#include "unitypes.h"
+
+/* Get common macros for C.  */
+#include "unused-parameter.h"
+
+/* Get bool.  */
+#include <stdbool.h>
+
+/* Get size_t.  */
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Conventions:
+
+   All functions prefixed with u8_ operate on UTF-8 encoded strings.
+   Their unit is an uint8_t (1 byte).
+
+   All functions prefixed with u16_ operate on UTF-16 encoded strings.
+   Their unit is an uint16_t (a 2-byte word).
+
+   All functions prefixed with u32_ operate on UCS-4 encoded strings.
+   Their unit is an uint32_t (a 4-byte word).
+
+   All argument pairs (s, n) denote a Unicode string s[0..n-1] with exactly
+   n units.
+
+   All arguments starting with "str" and the arguments of functions starting
+   with u8_str/u16_str/u32_str denote a NUL terminated string, i.e. a string
+   which terminates at the first NUL unit.  This termination unit is
+   considered part of the string for all memory allocation purposes, but
+   is not considered part of the string for all other logical purposes.
+
+   Functions returning a string result take a (resultbuf, lengthp) argument
+   pair.  If resultbuf is not NULL and the result fits into *lengthp units,
+   it is put in resultbuf, and resultbuf is returned.  Otherwise, a freshly
+   allocated string is returned.  In both cases, *lengthp is set to the
+   length (number of units) of the returned string.  In case of error,
+   NULL is returned and errno is set.  */
+
+
+/* Elementary string checks.  */
+
+/* Check whether an UTF-8 string is well-formed.
+   Return NULL if valid, or a pointer to the first invalid unit otherwise.  */
+extern const uint8_t *
+       u8_check (const uint8_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+
+/* Check whether an UTF-16 string is well-formed.
+   Return NULL if valid, or a pointer to the first invalid unit otherwise.  */
+extern const uint16_t *
+       u16_check (const uint16_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+
+/* Check whether an UCS-4 string is well-formed.
+   Return NULL if valid, or a pointer to the first invalid unit otherwise.  */
+extern const uint32_t *
+       u32_check (const uint32_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+
+
+/* Elementary string conversions.  */
+
+/* Convert an UTF-8 string to an UTF-16 string.  */
+extern uint16_t *
+       u8_to_u16 (const uint8_t *s, size_t n, uint16_t *resultbuf,
+                  size_t *lengthp);
+
+/* Convert an UTF-8 string to an UCS-4 string.  */
+extern uint32_t *
+       u8_to_u32 (const uint8_t *s, size_t n, uint32_t *resultbuf,
+                  size_t *lengthp);
+
+/* Convert an UTF-16 string to an UTF-8 string.  */
+extern uint8_t *
+       u16_to_u8 (const uint16_t *s, size_t n, uint8_t *resultbuf,
+                  size_t *lengthp);
+
+/* Convert an UTF-16 string to an UCS-4 string.  */
+extern uint32_t *
+       u16_to_u32 (const uint16_t *s, size_t n, uint32_t *resultbuf,
+                   size_t *lengthp);
+
+/* Convert an UCS-4 string to an UTF-8 string.  */
+extern uint8_t *
+       u32_to_u8 (const uint32_t *s, size_t n, uint8_t *resultbuf,
+                  size_t *lengthp);
+
+/* Convert an UCS-4 string to an UTF-16 string.  */
+extern uint16_t *
+       u32_to_u16 (const uint32_t *s, size_t n, uint16_t *resultbuf,
+                   size_t *lengthp);
+
+
+/* Elementary string functions.  */
+
+/* Return the length (number of units) of the first character in S, which is
+   no longer than N.  Return 0 if it is the NUL character.  Return -1 upon
+   failure.  */
+/* Similar to mblen(), except that s must not be NULL.  */
+extern int
+       u8_mblen (const uint8_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u16_mblen (const uint16_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u32_mblen (const uint32_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+
+/* Return the length (number of units) of the first character in S, putting
+   its 'ucs4_t' representation in *PUC.  Upon failure, *PUC is set to 0xfffd,
+   and an appropriate number of units is returned.
+   The number of available units, N, must be > 0.  */
+/* Similar to mbtowc(), except that puc and s must not be NULL, n must be > 0,
+   and the NUL character is not treated specially.  */
+/* The variants with _safe suffix are safe, even if the library is compiled
+   without --enable-safety.  */
+
+#if GNULIB_UNISTR_U8_MBTOUC_UNSAFE || HAVE_LIBUNISTRING
+# if !HAVE_INLINE
+extern int
+       u8_mbtouc_unsafe (ucs4_t *puc, const uint8_t *s, size_t n);
+# else
+extern int
+       u8_mbtouc_unsafe_aux (ucs4_t *puc, const uint8_t *s, size_t n);
+static inline int
+u8_mbtouc_unsafe (ucs4_t *puc, const uint8_t *s, size_t n)
+{
+  uint8_t c = *s;
+
+  if (c < 0x80)
+    {
+      *puc = c;
+      return 1;
+    }
+  else
+    return u8_mbtouc_unsafe_aux (puc, s, n);
+}
+# endif
+#endif
+
+#if GNULIB_UNISTR_U16_MBTOUC_UNSAFE || HAVE_LIBUNISTRING
+# if !HAVE_INLINE
+extern int
+       u16_mbtouc_unsafe (ucs4_t *puc, const uint16_t *s, size_t n);
+# else
+extern int
+       u16_mbtouc_unsafe_aux (ucs4_t *puc, const uint16_t *s, size_t n);
+static inline int
+u16_mbtouc_unsafe (ucs4_t *puc, const uint16_t *s, size_t n)
+{
+  uint16_t c = *s;
+
+  if (c < 0xd800 || c >= 0xe000)
+    {
+      *puc = c;
+      return 1;
+    }
+  else
+    return u16_mbtouc_unsafe_aux (puc, s, n);
+}
+# endif
+#endif
+
+#if GNULIB_UNISTR_U32_MBTOUC_UNSAFE || HAVE_LIBUNISTRING
+# if !HAVE_INLINE
+extern int
+       u32_mbtouc_unsafe (ucs4_t *puc, const uint32_t *s, size_t n);
+# else
+static inline int
+u32_mbtouc_unsafe (ucs4_t *puc,
+                   const uint32_t *s, size_t n _GL_UNUSED_PARAMETER)
+{
+  uint32_t c = *s;
+
+#  if CONFIG_UNICODE_SAFETY
+  if (c < 0xd800 || (c >= 0xe000 && c < 0x110000))
+#  endif
+    *puc = c;
+#  if CONFIG_UNICODE_SAFETY
+  else
+    /* invalid multibyte character */
+    *puc = 0xfffd;
+#  endif
+  return 1;
+}
+# endif
+#endif
+
+#if GNULIB_UNISTR_U8_MBTOUC || HAVE_LIBUNISTRING
+# if !HAVE_INLINE
+extern int
+       u8_mbtouc (ucs4_t *puc, const uint8_t *s, size_t n);
+# else
+extern int
+       u8_mbtouc_aux (ucs4_t *puc, const uint8_t *s, size_t n);
+static inline int
+u8_mbtouc (ucs4_t *puc, const uint8_t *s, size_t n)
+{
+  uint8_t c = *s;
+
+  if (c < 0x80)
+    {
+      *puc = c;
+      return 1;
+    }
+  else
+    return u8_mbtouc_aux (puc, s, n);
+}
+# endif
+#endif
+
+#if GNULIB_UNISTR_U16_MBTOUC || HAVE_LIBUNISTRING
+# if !HAVE_INLINE
+extern int
+       u16_mbtouc (ucs4_t *puc, const uint16_t *s, size_t n);
+# else
+extern int
+       u16_mbtouc_aux (ucs4_t *puc, const uint16_t *s, size_t n);
+static inline int
+u16_mbtouc (ucs4_t *puc, const uint16_t *s, size_t n)
+{
+  uint16_t c = *s;
+
+  if (c < 0xd800 || c >= 0xe000)
+    {
+      *puc = c;
+      return 1;
+    }
+  else
+    return u16_mbtouc_aux (puc, s, n);
+}
+# endif
+#endif
+
+#if GNULIB_UNISTR_U32_MBTOUC || HAVE_LIBUNISTRING
+# if !HAVE_INLINE
+extern int
+       u32_mbtouc (ucs4_t *puc, const uint32_t *s, size_t n);
+# else
+static inline int
+u32_mbtouc (ucs4_t *puc, const uint32_t *s, size_t n _GL_UNUSED_PARAMETER)
+{
+  uint32_t c = *s;
+
+  if (c < 0xd800 || (c >= 0xe000 && c < 0x110000))
+    *puc = c;
+  else
+    /* invalid multibyte character */
+    *puc = 0xfffd;
+  return 1;
+}
+# endif
+#endif
+
+/* Return the length (number of units) of the first character in S, putting
+   its 'ucs4_t' representation in *PUC.  Upon failure, *PUC is set to 0xfffd,
+   and -1 is returned for an invalid sequence of units, -2 is returned for an
+   incomplete sequence of units.
+   The number of available units, N, must be > 0.  */
+/* Similar to u*_mbtouc(), except that the return value gives more details
+   about the failure, similar to mbrtowc().  */
+
+#if GNULIB_UNISTR_U8_MBTOUCR || HAVE_LIBUNISTRING
+extern int
+       u8_mbtoucr (ucs4_t *puc, const uint8_t *s, size_t n);
+#endif
+
+#if GNULIB_UNISTR_U16_MBTOUCR || HAVE_LIBUNISTRING
+extern int
+       u16_mbtoucr (ucs4_t *puc, const uint16_t *s, size_t n);
+#endif
+
+#if GNULIB_UNISTR_U32_MBTOUCR || HAVE_LIBUNISTRING
+extern int
+       u32_mbtoucr (ucs4_t *puc, const uint32_t *s, size_t n);
+#endif
+
+/* Put the multibyte character represented by UC in S, returning its
+   length.  Return -1 upon failure, -2 if the number of available units, N,
+   is too small.  The latter case cannot occur if N >= 6/2/1, respectively.  */
+/* Similar to wctomb(), except that s must not be NULL, and the argument n
+   must be specified.  */
+
+#if GNULIB_UNISTR_U8_UCTOMB || HAVE_LIBUNISTRING
+/* Auxiliary function, also used by u8_chr, u8_strchr, u8_strrchr.  */
+extern int
+       u8_uctomb_aux (uint8_t *s, ucs4_t uc, int n);
+# if !HAVE_INLINE
+extern int
+       u8_uctomb (uint8_t *s, ucs4_t uc, int n);
+# else
+static inline int
+u8_uctomb (uint8_t *s, ucs4_t uc, int n)
+{
+  if (uc < 0x80 && n > 0)
+    {
+      s[0] = uc;
+      return 1;
+    }
+  else
+    return u8_uctomb_aux (s, uc, n);
+}
+# endif
+#endif
+
+#if GNULIB_UNISTR_U16_UCTOMB || HAVE_LIBUNISTRING
+/* Auxiliary function, also used by u16_chr, u16_strchr, u16_strrchr.  */
+extern int
+       u16_uctomb_aux (uint16_t *s, ucs4_t uc, int n);
+# if !HAVE_INLINE
+extern int
+       u16_uctomb (uint16_t *s, ucs4_t uc, int n);
+# else
+static inline int
+u16_uctomb (uint16_t *s, ucs4_t uc, int n)
+{
+  if (uc < 0xd800 && n > 0)
+    {
+      s[0] = uc;
+      return 1;
+    }
+  else
+    return u16_uctomb_aux (s, uc, n);
+}
+# endif
+#endif
+
+#if GNULIB_UNISTR_U32_UCTOMB || HAVE_LIBUNISTRING
+# if !HAVE_INLINE
+extern int
+       u32_uctomb (uint32_t *s, ucs4_t uc, int n);
+# else
+static inline int
+u32_uctomb (uint32_t *s, ucs4_t uc, int n)
+{
+  if (uc < 0xd800 || (uc >= 0xe000 && uc < 0x110000))
+    {
+      if (n > 0)
+        {
+          *s = uc;
+          return 1;
+        }
+      else
+        return -2;
+    }
+  else
+    return -1;
+}
+# endif
+#endif
+
+/* Copy N units from SRC to DEST.  */
+/* Similar to memcpy().  */
+extern uint8_t *
+       u8_cpy (uint8_t *dest, const uint8_t *src, size_t n);
+extern uint16_t *
+       u16_cpy (uint16_t *dest, const uint16_t *src, size_t n);
+extern uint32_t *
+       u32_cpy (uint32_t *dest, const uint32_t *src, size_t n);
+
+/* Copy N units from SRC to DEST, guaranteeing correct behavior for
+   overlapping memory areas.  */
+/* Similar to memmove().  */
+extern uint8_t *
+       u8_move (uint8_t *dest, const uint8_t *src, size_t n);
+extern uint16_t *
+       u16_move (uint16_t *dest, const uint16_t *src, size_t n);
+extern uint32_t *
+       u32_move (uint32_t *dest, const uint32_t *src, size_t n);
+
+/* Set the first N characters of S to UC.  UC should be a character that
+   occupies only 1 unit.  */
+/* Similar to memset().  */
+extern uint8_t *
+       u8_set (uint8_t *s, ucs4_t uc, size_t n);
+extern uint16_t *
+       u16_set (uint16_t *s, ucs4_t uc, size_t n);
+extern uint32_t *
+       u32_set (uint32_t *s, ucs4_t uc, size_t n);
+
+/* Compare S1 and S2, each of length N.  */
+/* Similar to memcmp().  */
+extern int
+       u8_cmp (const uint8_t *s1, const uint8_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u16_cmp (const uint16_t *s1, const uint16_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u32_cmp (const uint32_t *s1, const uint32_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
+
+/* Compare S1 and S2.  */
+/* Similar to the gnulib function memcmp2().  */
+extern int
+       u8_cmp2 (const uint8_t *s1, size_t n1, const uint8_t *s2, size_t n2)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u16_cmp2 (const uint16_t *s1, size_t n1, const uint16_t *s2, size_t n2)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u32_cmp2 (const uint32_t *s1, size_t n1, const uint32_t *s2, size_t n2)
+       _UC_ATTRIBUTE_PURE;
+
+/* Search the string at S for UC.  */
+/* Similar to memchr().  */
+extern uint8_t *
+       u8_chr (const uint8_t *s, size_t n, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+extern uint16_t *
+       u16_chr (const uint16_t *s, size_t n, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+extern uint32_t *
+       u32_chr (const uint32_t *s, size_t n, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+
+/* Count the number of Unicode characters in the N units from S.  */
+/* Similar to mbsnlen().  */
+extern size_t
+       u8_mbsnlen (const uint8_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u16_mbsnlen (const uint16_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u32_mbsnlen (const uint32_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
+
+/* Elementary string functions with memory allocation.  */
+
+/* Make a freshly allocated copy of S, of length N.  */
+extern uint8_t *
+       u8_cpy_alloc (const uint8_t *s, size_t n);
+extern uint16_t *
+       u16_cpy_alloc (const uint16_t *s, size_t n);
+extern uint32_t *
+       u32_cpy_alloc (const uint32_t *s, size_t n);
+
+/* Elementary string functions on NUL terminated strings.  */
+
+/* Return the length (number of units) of the first character in S.
+   Return 0 if it is the NUL character.  Return -1 upon failure.  */
+extern int
+       u8_strmblen (const uint8_t *s)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u16_strmblen (const uint16_t *s)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u32_strmblen (const uint32_t *s)
+       _UC_ATTRIBUTE_PURE;
+
+/* Return the length (number of units) of the first character in S, putting
+   its 'ucs4_t' representation in *PUC.  Return 0 if it is the NUL
+   character.  Return -1 upon failure.  */
+extern int
+       u8_strmbtouc (ucs4_t *puc, const uint8_t *s);
+extern int
+       u16_strmbtouc (ucs4_t *puc, const uint16_t *s);
+extern int
+       u32_strmbtouc (ucs4_t *puc, const uint32_t *s);
+
+/* Forward iteration step.  Advances the pointer past the next character,
+   or returns NULL if the end of the string has been reached.  Puts the
+   character's 'ucs4_t' representation in *PUC.  */
+extern const uint8_t *
+       u8_next (ucs4_t *puc, const uint8_t *s);
+extern const uint16_t *
+       u16_next (ucs4_t *puc, const uint16_t *s);
+extern const uint32_t *
+       u32_next (ucs4_t *puc, const uint32_t *s);
+
+/* Backward iteration step.  Advances the pointer to point to the previous
+   character, or returns NULL if the beginning of the string had been reached.
+   Puts the character's 'ucs4_t' representation in *PUC.  */
+extern const uint8_t *
+       u8_prev (ucs4_t *puc, const uint8_t *s, const uint8_t *start);
+extern const uint16_t *
+       u16_prev (ucs4_t *puc, const uint16_t *s, const uint16_t *start);
+extern const uint32_t *
+       u32_prev (ucs4_t *puc, const uint32_t *s, const uint32_t *start);
+
+/* Return the number of units in S.  */
+/* Similar to strlen(), wcslen().  */
+extern size_t
+       u8_strlen (const uint8_t *s)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u16_strlen (const uint16_t *s)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u32_strlen (const uint32_t *s)
+       _UC_ATTRIBUTE_PURE;
+
+/* Return the number of units in S, but at most MAXLEN.  */
+/* Similar to strnlen(), wcsnlen().  */
+extern size_t
+       u8_strnlen (const uint8_t *s, size_t maxlen)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u16_strnlen (const uint16_t *s, size_t maxlen)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u32_strnlen (const uint32_t *s, size_t maxlen)
+       _UC_ATTRIBUTE_PURE;
+
+/* Copy SRC to DEST.  */
+/* Similar to strcpy(), wcscpy().  */
+extern uint8_t *
+       u8_strcpy (uint8_t *dest, const uint8_t *src);
+extern uint16_t *
+       u16_strcpy (uint16_t *dest, const uint16_t *src);
+extern uint32_t *
+       u32_strcpy (uint32_t *dest, const uint32_t *src);
+
+/* Copy SRC to DEST, returning the address of the terminating NUL in DEST.  */
+/* Similar to stpcpy().  */
+extern uint8_t *
+       u8_stpcpy (uint8_t *dest, const uint8_t *src);
+extern uint16_t *
+       u16_stpcpy (uint16_t *dest, const uint16_t *src);
+extern uint32_t *
+       u32_stpcpy (uint32_t *dest, const uint32_t *src);
+
+/* Copy no more than N units of SRC to DEST.  */
+/* Similar to strncpy(), wcsncpy().  */
+extern uint8_t *
+       u8_strncpy (uint8_t *dest, const uint8_t *src, size_t n);
+extern uint16_t *
+       u16_strncpy (uint16_t *dest, const uint16_t *src, size_t n);
+extern uint32_t *
+       u32_strncpy (uint32_t *dest, const uint32_t *src, size_t n);
+
+/* Copy no more than N units of SRC to DEST.  Return a pointer past the last
+   non-NUL unit written into DEST.  */
+/* Similar to stpncpy().  */
+extern uint8_t *
+       u8_stpncpy (uint8_t *dest, const uint8_t *src, size_t n);
+extern uint16_t *
+       u16_stpncpy (uint16_t *dest, const uint16_t *src, size_t n);
+extern uint32_t *
+       u32_stpncpy (uint32_t *dest, const uint32_t *src, size_t n);
+
+/* Append SRC onto DEST.  */
+/* Similar to strcat(), wcscat().  */
+extern uint8_t *
+       u8_strcat (uint8_t *dest, const uint8_t *src);
+extern uint16_t *
+       u16_strcat (uint16_t *dest, const uint16_t *src);
+extern uint32_t *
+       u32_strcat (uint32_t *dest, const uint32_t *src);
+
+/* Append no more than N units of SRC onto DEST.  */
+/* Similar to strncat(), wcsncat().  */
+extern uint8_t *
+       u8_strncat (uint8_t *dest, const uint8_t *src, size_t n);
+extern uint16_t *
+       u16_strncat (uint16_t *dest, const uint16_t *src, size_t n);
+extern uint32_t *
+       u32_strncat (uint32_t *dest, const uint32_t *src, size_t n);
+
+/* Compare S1 and S2.  */
+/* Similar to strcmp(), wcscmp().  */
+#ifdef __sun
+/* Avoid a collision with the u8_strcmp() function in Solaris 11 libc.  */
+extern int
+       u8_strcmp_gnu (const uint8_t *s1, const uint8_t *s2)
+       _UC_ATTRIBUTE_PURE;
+# define u8_strcmp u8_strcmp_gnu
+#else
+extern int
+       u8_strcmp (const uint8_t *s1, const uint8_t *s2)
+       _UC_ATTRIBUTE_PURE;
+#endif
+extern int
+       u16_strcmp (const uint16_t *s1, const uint16_t *s2)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u32_strcmp (const uint32_t *s1, const uint32_t *s2)
+       _UC_ATTRIBUTE_PURE;
+
+/* Compare S1 and S2 using the collation rules of the current locale.
+   Return -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2.
+   Upon failure, set errno and return any value.  */
+/* Similar to strcoll(), wcscoll().  */
+extern int
+       u8_strcoll (const uint8_t *s1, const uint8_t *s2);
+extern int
+       u16_strcoll (const uint16_t *s1, const uint16_t *s2);
+extern int
+       u32_strcoll (const uint32_t *s1, const uint32_t *s2);
+
+/* Compare no more than N units of S1 and S2.  */
+/* Similar to strncmp(), wcsncmp().  */
+extern int
+       u8_strncmp (const uint8_t *s1, const uint8_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u16_strncmp (const uint16_t *s1, const uint16_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
+extern int
+       u32_strncmp (const uint32_t *s1, const uint32_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
+
+/* Duplicate S, returning an identical malloc'd string.  */
+/* Similar to strdup(), wcsdup().  */
+extern uint8_t *
+       u8_strdup (const uint8_t *s);
+extern uint16_t *
+       u16_strdup (const uint16_t *s);
+extern uint32_t *
+       u32_strdup (const uint32_t *s);
+
+/* Find the first occurrence of UC in STR.  */
+/* Similar to strchr(), wcschr().  */
+extern uint8_t *
+       u8_strchr (const uint8_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+extern uint16_t *
+       u16_strchr (const uint16_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+extern uint32_t *
+       u32_strchr (const uint32_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+
+/* Find the last occurrence of UC in STR.  */
+/* Similar to strrchr(), wcsrchr().  */
+extern uint8_t *
+       u8_strrchr (const uint8_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+extern uint16_t *
+       u16_strrchr (const uint16_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+extern uint32_t *
+       u32_strrchr (const uint32_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
+
+/* Return the length of the initial segment of STR which consists entirely
+   of Unicode characters not in REJECT.  */
+/* Similar to strcspn(), wcscspn().  */
+extern size_t
+       u8_strcspn (const uint8_t *str, const uint8_t *reject)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u16_strcspn (const uint16_t *str, const uint16_t *reject)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u32_strcspn (const uint32_t *str, const uint32_t *reject)
+       _UC_ATTRIBUTE_PURE;
+
+/* Return the length of the initial segment of STR which consists entirely
+   of Unicode characters in ACCEPT.  */
+/* Similar to strspn(), wcsspn().  */
+extern size_t
+       u8_strspn (const uint8_t *str, const uint8_t *accept)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u16_strspn (const uint16_t *str, const uint16_t *accept)
+       _UC_ATTRIBUTE_PURE;
+extern size_t
+       u32_strspn (const uint32_t *str, const uint32_t *accept)
+       _UC_ATTRIBUTE_PURE;
+
+/* Find the first occurrence in STR of any character in ACCEPT.  */
+/* Similar to strpbrk(), wcspbrk().  */
+extern uint8_t *
+       u8_strpbrk (const uint8_t *str, const uint8_t *accept)
+       _UC_ATTRIBUTE_PURE;
+extern uint16_t *
+       u16_strpbrk (const uint16_t *str, const uint16_t *accept)
+       _UC_ATTRIBUTE_PURE;
+extern uint32_t *
+       u32_strpbrk (const uint32_t *str, const uint32_t *accept)
+       _UC_ATTRIBUTE_PURE;
+
+/* Find the first occurrence of NEEDLE in HAYSTACK.  */
+/* Similar to strstr(), wcsstr().  */
+extern uint8_t *
+       u8_strstr (const uint8_t *haystack, const uint8_t *needle)
+       _UC_ATTRIBUTE_PURE;
+extern uint16_t *
+       u16_strstr (const uint16_t *haystack, const uint16_t *needle)
+       _UC_ATTRIBUTE_PURE;
+extern uint32_t *
+       u32_strstr (const uint32_t *haystack, const uint32_t *needle)
+       _UC_ATTRIBUTE_PURE;
+
+/* Test whether STR starts with PREFIX.  */
+extern bool
+       u8_startswith (const uint8_t *str, const uint8_t *prefix)
+       _UC_ATTRIBUTE_PURE;
+extern bool
+       u16_startswith (const uint16_t *str, const uint16_t *prefix)
+       _UC_ATTRIBUTE_PURE;
+extern bool
+       u32_startswith (const uint32_t *str, const uint32_t *prefix)
+       _UC_ATTRIBUTE_PURE;
+
+/* Test whether STR ends with SUFFIX.  */
+extern bool
+       u8_endswith (const uint8_t *str, const uint8_t *suffix)
+       _UC_ATTRIBUTE_PURE;
+extern bool
+       u16_endswith (const uint16_t *str, const uint16_t *suffix)
+       _UC_ATTRIBUTE_PURE;
+extern bool
+       u32_endswith (const uint32_t *str, const uint32_t *suffix)
+       _UC_ATTRIBUTE_PURE;
+
+/* Divide STR into tokens separated by characters in DELIM.
+   This interface is actually more similar to wcstok than to strtok.  */
+/* Similar to strtok_r(), wcstok().  */
+extern uint8_t *
+       u8_strtok (uint8_t *str, const uint8_t *delim, uint8_t **ptr);
+extern uint16_t *
+       u16_strtok (uint16_t *str, const uint16_t *delim, uint16_t **ptr);
+extern uint32_t *
+       u32_strtok (uint32_t *str, const uint32_t *delim, uint32_t **ptr);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNISTR_H */
Index: libidn-1.10/lib/gl/unitypes.in.h
===================================================================
--- /dev/null
+++ libidn-1.10/lib/gl/unitypes.in.h
@@ -0,0 +1,46 @@
+/* Elementary types and macros for the GNU UniString library.
+   Copyright (C) 2002, 2005-2006, 2009-2013 Free Software Foundation, Inc.
+
+   This program 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 program 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 program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _UNITYPES_H
+#define _UNITYPES_H
+
+/* Get uint8_t, uint16_t, uint32_t.  */
+#include <stdint.h>
+
+/* Type representing a Unicode character.  */
+typedef uint32_t ucs4_t;
+
+/* Attribute of a function whose result depends only on the arguments
+   (not pointers!) and which has no side effects.  */
+#ifndef _UC_ATTRIBUTE_CONST
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#  define _UC_ATTRIBUTE_CONST __attribute__ ((__const__))
+# else
+#  define _UC_ATTRIBUTE_CONST
+# endif
+#endif
+
+/* Attribute of a function whose result depends only on the arguments
+   (possibly pointers) and global memory, and which has no side effects.  */
+#ifndef _UC_ATTRIBUTE_PURE
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#  define _UC_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define _UC_ATTRIBUTE_PURE
+# endif
+#endif
+
+#endif /* _UNITYPES_H */
Index: libidn-1.10/lib/gl/unused-parameter.h
===================================================================
--- /dev/null
+++ libidn-1.10/lib/gl/unused-parameter.h
@@ -0,0 +1,36 @@
+/* A C macro for declaring that specific function parameters are not used.
+   Copyright (C) 2008-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* _GL_UNUSED_PARAMETER is a marker that can be appended to function parameter
+   declarations for parameters that are not used.  This helps to reduce
+   warnings, such as from GCC -Wunused-parameter.  The syntax is as follows:
+       type param _GL_UNUSED_PARAMETER
+   or more generally
+       param_decl _GL_UNUSED_PARAMETER
+   For example:
+       int param _GL_UNUSED_PARAMETER
+       int *(*param)(void) _GL_UNUSED_PARAMETER
+   Other possible, but obscure and discouraged syntaxes:
+       int _GL_UNUSED_PARAMETER *(*param)(void)
+       _GL_UNUSED_PARAMETER int *(*param)(void)
+ */
+#ifndef _GL_UNUSED_PARAMETER
+# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+#  define _GL_UNUSED_PARAMETER __attribute__ ((__unused__))
+# else
+#  define _GL_UNUSED_PARAMETER
+# endif
+#endif
Index: libidn-1.10/lib/stringprep.h.in
===================================================================
--- libidn-1.10.orig/lib/stringprep.h.in
+++ libidn-1.10/lib/stringprep.h.in
@@ -58,6 +58,7 @@ extern "C"
     STRINGPREP_PROFILE_ERROR = 101,
     STRINGPREP_FLAG_ERROR = 102,
     STRINGPREP_UNKNOWN_PROFILE = 103,
+    STRINGPREP_ICONV_ERROR = 104,
     /* Internal errors. */
     STRINGPREP_NFKC_FAILED = 200,
     STRINGPREP_MALLOC_ERROR = 201
