CVE-2019-12290: Improper Input Validation (CWE-20)
value: GNU libidn2 before 2.2.0 fails to perform the roundtrip checks specified in RFC3490 Section 4.2 when converting A-labels to U-labels. This makes it possible in some circumstances for one domain to impersonate another. By creating a malicious domain that matches a target domain except for the inclusion of certain punycoded Unicode characters (that would be discarded when converted first to a Unicode label and then back to an ASCII label), arbitrary domains can be impersonated.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 7.5
Published: 2019-10-22T16:15Z
Repository: https://gitlab.com/libidn/libidn2
Language: C
Files changed: lib/error.c, lib/idn2.h.in, lib/lookup.c, src/blurbs.h, src/idn2.c, src/idn2.ggo
Commit date: 2019-04-10 17:27:39 +0000
Commit message: Perform A-Label roundtrip for lookup functions by default

This adds another check to avoid unexpected results.
It was a longstanding FIXME.

Thanks to  Jonathan Birch of Microsoft Corporation,
Florian Weimer (GNU glibc) and Nikos Mavrogiannopoulos (GnuTLS)
for investigation, discussion and testing.

Diff: diff --git a/lib/error.c b/lib/error.c
index 0304044e..8483f301 100644
--- a/lib/error.c
+++ b/lib/error.c
@@ -75,10 +75,11 @@ idn2_strerror (int rc)
     case IDN2_UNASSIGNED: return _("string contains unassigned code point");
     case IDN2_BIDI: return _("string has forbidden bi-directional properties");
     case IDN2_DOT_IN_LABEL: return _("domain label has forbidden dot (TR46)");
     case IDN2_INVALID_TRANSITIONAL: return _("domain label has character forbidden in transitional mode (TR46)");
     case IDN2_INVALID_NONTRANSITIONAL: return _("domain label has character forbidden in non-transitional mode (TR46)");
+    case IDN2_ALABEL_ROUNDTRIP_FAILED: return _("Alabel roundtrip failed");
     default: return _("Unknown error");
     }
 }
 
 #define ERR2STR(name) #name
@@ -127,8 +128,9 @@ idn2_strerror_name (int rc)
     case IDN2_UNASSIGNED: return ERR2STR (IDN2_UNASSIGNED);
     case IDN2_BIDI: return ERR2STR (IDN2_BIDI);
     case IDN2_DOT_IN_LABEL: return ERR2STR (IDN2_DOT_IN_LABEL);
     case IDN2_INVALID_TRANSITIONAL: return ERR2STR (IDN2_INVALID_TRANSITIONAL);
     case IDN2_INVALID_NONTRANSITIONAL: return ERR2STR (IDN2_INVALID_NONTRANSITIONAL);
+    case IDN2_ALABEL_ROUNDTRIP_FAILED: return ERR2STR (IDN2_ALABEL_ROUNDTRIP_FAILED);
     default: return "IDN2_UNKNOWN";
     }
 }
diff --git a/lib/idn2.h.in b/lib/idn2.h.in
index 695662b1..c7835b09 100644
--- a/lib/idn2.h.in
+++ b/lib/idn2.h.in
@@ -176,14 +176,15 @@ extern "C"
 #define IDN2_DOMAIN_MAX_LENGTH 255
 
 /**
  * idn2_flags:
  * @IDN2_NFC_INPUT: Normalize input string using normalization form C.
- * @IDN2_ALABEL_ROUNDTRIP: Perform optional IDNA2008 lookup roundtrip check (not implemented yet).
- * @IDN2_NO_TR46: Disable Unicode TR46 processing (default).
+ * @IDN2_ALABEL_ROUNDTRIP: Perform optional IDNA2008 lookup roundtrip check (default).
+ * @IDN2_NO_ALABEL_ROUNDTRIP: Disable ALabel lookup roundtrip check.
+ * @IDN2_NO_TR46: Disable Unicode TR46 processing.
  * @IDN2_TRANSITIONAL: Perform Unicode TR46 transitional processing.
- * @IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional processing.
+ * @IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional processing (default).
  * @IDN2_ALLOW_UNASSIGNED: Libidn compatibility flag, unused.
  * @IDN2_USE_STD3_ASCII_RULES: Use STD3 ASCII rules.
  * This is a #TR46 only flag, and will be ignored when set without either
  * @IDN2_TRANSITIONAL or @IDN2_NONTRANSITIONAL.
  *
@@ -196,11 +197,12 @@ extern "C"
     IDN2_ALABEL_ROUNDTRIP = 2,
     IDN2_TRANSITIONAL = 4,
     IDN2_NONTRANSITIONAL = 8,
     IDN2_ALLOW_UNASSIGNED = 16,
     IDN2_USE_STD3_ASCII_RULES = 32,
-    IDN2_NO_TR46 = 64
+    IDN2_NO_TR46 = 64,
+    IDN2_NO_ALABEL_ROUNDTRIP = 128
   } idn2_flags;
 
 /* IDNA2008 with UTF-8 encoded inputs. */
 
   extern _IDN2_API int
@@ -247,10 +249,11 @@ extern "C"
  * @IDN2_UNASSIGNED: String has forbidden unassigned character.
  * @IDN2_BIDI: String has forbidden bi-directional properties.
  * @IDN2_DOT_IN_LABEL: Label has forbidden dot (TR46).
  * @IDN2_INVALID_TRANSITIONAL: Label has character forbidden in transitional mode (TR46).
  * @IDN2_INVALID_NONTRANSITIONAL: Label has character forbidden in non-transitional mode (TR46).
+ * @IDN2_ALABEL_ROUNDTRIP_FAILED: ALabel -> Ulabel -> ALabel result differs from input.
  *
  * Return codes for IDN2 functions.  All return codes are negative
  * except for the successful code IDN2_OK which are guaranteed to be
  * 0.  Positive values are reserved for non-error return codes.
  *
@@ -285,10 +288,11 @@ extern "C"
     IDN2_UNASSIGNED = -309,
     IDN2_BIDI = -310,
     IDN2_DOT_IN_LABEL = -311,
     IDN2_INVALID_TRANSITIONAL = -312,
     IDN2_INVALID_NONTRANSITIONAL = -313,
+    IDN2_ALABEL_ROUNDTRIP_FAILED = -314,
   } idn2_rc;
 
 /* Auxiliary functions. */
 
   extern _IDN2_API G_GNUC_DEPRECATED int
diff --git a/lib/lookup.c b/lib/lookup.c
index 0342ee5b..1dd0e971 100644
--- a/lib/lookup.c
+++ b/lib/lookup.c
@@ -49,10 +49,13 @@ static int set_default_flags(int *flags)
     return IDN2_INVALID_FLAGS;
 
   if (((*flags) & (IDN2_TRANSITIONAL|IDN2_NONTRANSITIONAL)) && ((*flags) & IDN2_NO_TR46))
     return IDN2_INVALID_FLAGS;
 
+  if (((*flags) & IDN2_ALABEL_ROUNDTRIP) && ((*flags) & IDN2_NO_ALABEL_ROUNDTRIP))
+    return IDN2_INVALID_FLAGS;
+
   if (!((*flags) & (IDN2_NO_TR46|IDN2_TRANSITIONAL)))
     *flags |= IDN2_NONTRANSITIONAL;
 
   return IDN2_OK;
 }
@@ -61,40 +64,57 @@ static int
 label (const uint8_t * src, size_t srclen, uint8_t * dst, size_t * dstlen,
        int flags)
 {
   size_t plen;
   uint32_t *p;
-  int rc;
-  size_t tmpl;
-
-  if (_idn2_ascii_p (src, srclen))
-    {
-      if (flags & IDN2_ALABEL_ROUNDTRIP)
-	/* FIXME implement this MAY:
-
-	   If the input to this procedure appears to be an A-label
-	   (i.e., it starts in "xn--", interpreted
-	   case-insensitively), the lookup application MAY attempt to
-	   convert it to a U-label, first ensuring that the A-label is
-	   entirely in lowercase (converting it to lowercase if
-	   necessary), and apply the tests of Section 5.4 and the
-	   conversion of Section 5.5 to that form. */
-	return IDN2_INVALID_FLAGS;
+  const uint8_t *src_org = NULL;
+  uint8_t *src_allocated = NULL;
+  int rc, check_roundtrip = 0;
+  size_t tmpl, srclen_org = 0;
+  uint32_t label_u32[IDN2_LABEL_MAX_LENGTH];
+  size_t label32_len = IDN2_LABEL_MAX_LENGTH;
+
+  if (_idn2_ascii_p (src, srclen)) {
+    if (!(flags & IDN2_NO_ALABEL_ROUNDTRIP) && srclen >= 4 && memcmp (src, "xn--", 4) == 0) {
+      /*
+	 If the input to this procedure appears to be an A-label
+	 (i.e., it starts in "xn--", interpreted
+	 case-insensitively), the lookup application MAY attempt to
+	 convert it to a U-label, first ensuring that the A-label is
+	 entirely in lowercase (converting it to lowercase if
+	 necessary), and apply the tests of Section 5.4 and the
+	 conversion of Section 5.5 to that form. */
+      rc = _idn2_punycode_decode (srclen - 4, (char *) src + 4, &label32_len, label_u32);
+      if (rc)
+	return rc;
 
+      check_roundtrip = 1;
+      src_org = src;
+      srclen_org = srclen;
+
+      srclen = IDN2_LABEL_MAX_LENGTH;
+      src = src_allocated = u32_to_u8 (label_u32, label32_len, NULL, &srclen);
+      if (!src) {
+	if (errno == ENOMEM)
+	  return IDN2_MALLOC;
+	return IDN2_ENCODING_ERROR;
+      }
+    } else {
       if (srclen > IDN2_LABEL_MAX_LENGTH)
 	return IDN2_TOO_BIG_LABEL;
       if (srclen > *dstlen)
 	return IDN2_TOO_BIG_DOMAIN;
 
       memcpy (dst, src, srclen);
       *dstlen = srclen;
       return IDN2_OK;
     }
+  }
 
   rc = _idn2_u8_to_u32_nfc (src, srclen, &p, &plen, flags & IDN2_NFC_INPUT);
   if (rc != IDN2_OK)
-    return rc;
+    goto out;
 
   if (!(flags & IDN2_TRANSITIONAL))
     {
       rc = _idn2_label_test(
 	TEST_NFC |
@@ -108,12 +128,12 @@ label (const uint8_t * src, size_t srclen, uint8_t * dst, size_t * dstlen,
 	((flags & IDN2_USE_STD3_ASCII_RULES) ? 0 : TEST_ALLOW_STD3_DISALLOWED),
 	p, plen);
 
       if (rc != IDN2_OK)
 	{
-	  free(p);
-	  return rc;
+	  free (p);
+	  goto out;
 	}
     }
 
   dst[0] = 'x';
   dst[1] = 'n';
@@ -122,15 +142,29 @@ label (const uint8_t * src, size_t srclen, uint8_t * dst, size_t * dstlen,
 
   tmpl = *dstlen - 4;
   rc = _idn2_punycode_encode (plen, p, &tmpl, (char *) dst + 4);
   free (p);
   if (rc != IDN2_OK)
-    return rc;
+    goto out;
+
 
   *dstlen = 4 + tmpl;
 
-  return IDN2_OK;
+  if (check_roundtrip)
+    {
+      if (srclen_org != *dstlen || memcmp (src_org, dst, srclen_org))
+      {
+        rc = IDN2_ALABEL_ROUNDTRIP_FAILED;
+	goto out;
+      }
+    }
+
+  rc = IDN2_OK;
+
+out:
+  free (src_allocated);
+  return rc;
 }
 
 #define TR46_TRANSITIONAL_CHECK \
   (TEST_NFC | TEST_2HYPHEN | TEST_HYPHEN_STARTEND | TEST_LEADING_COMBINING | TEST_TRANSITIONAL)
 #define TR46_NONTRANSITIONAL_CHECK \
@@ -377,17 +411,21 @@ _tr46 (const uint8_t * domain_u8, uint8_t ** out, int flags)
  * must be encoded in UTF-8 and be in Unicode NFC form.
  *
  * Pass %IDN2_NFC_INPUT in @flags to convert input to NFC form before
  * further processing.  %IDN2_TRANSITIONAL and %IDN2_NONTRANSITIONAL
  * do already imply %IDN2_NFC_INPUT.
+ *
  * Pass %IDN2_ALABEL_ROUNDTRIP in @flags to
  * convert any input A-labels to U-labels and perform additional
- * testing (not implemented yet).
+ * testing. This is default since version 2.2.
+ * To switch this behavior off, pass IDN2_NO_ALABEL_ROUNDTRIP
+ *
  * Pass %IDN2_TRANSITIONAL to enable Unicode TR46
  * transitional processing, and %IDN2_NONTRANSITIONAL to enable
- * Unicode TR46 non-transitional processing.  Multiple flags may be
- * specified by binary or:ing them together.
+ * Unicode TR46 non-transitional processing.
+ *
+ * Multiple flags may be specified by binary or:ing them together.
  *
  * After version 2.0.3: %IDN2_USE_STD3_ASCII_RULES disabled by default.
  * Previously we were eliminating non-STD3 characters from domain strings
  * such as _443._tcp.example.com, or IPs 1.2.3.4/24 provided to libidn2
  * functions. That was an unexpected regression for applications switching
@@ -501,18 +539,23 @@ idn2_lookup_u8 (const uint8_t * src, uint8_t ** lookupname, int flags)
  * Perform IDNA2008 lookup string conversion on domain name @src, as
  * described in section 5 of RFC 5891.  Note that the input is assumed
  * to be encoded in the locale's default coding system, and will be
  * transcoded to UTF-8 and NFC normalized by this function.
  *
- * Pass %IDN2_ALABEL_ROUNDTRIP in @flags to convert any input A-labels
- * to U-labels and perform additional testing.  Pass
- * %IDN2_TRANSITIONAL to enable Unicode TR46 transitional processing,
+ * Pass %IDN2_ALABEL_ROUNDTRIP in @flags to
+ * convert any input A-labels to U-labels and perform additional
+ * testing. This is default since version 2.2.
+ * To switch this behavior off, pass IDN2_NO_ALABEL_ROUNDTRIP
+ *
+ * Pass %IDN2_TRANSITIONAL to enable Unicode TR46 transitional processing,
  * and %IDN2_NONTRANSITIONAL to enable Unicode TR46 non-transitional
- * processing.  Multiple flags may be specified by binary or:ing them
- * together, for example %IDN2_ALABEL_ROUNDTRIP |
- * %IDN2_NONTRANSITIONAL.  The %IDN2_NFC_INPUT in @flags is always
- * enabled in this function.
+ * processing.
+ *
+ * Multiple flags may be specified by binary or:ing them together, for
+ * example %IDN2_ALABEL_ROUNDTRIP | %IDN2_NONTRANSITIONAL.
+ *
+ * The %IDN2_NFC_INPUT in @flags is always enabled in this function.
  *
  * After version 0.11: @lookupname may be NULL to test lookup of @src
  * without allocating memory.
  *
  * Returns: On successful conversion %IDN2_OK is returned, if
diff --git a/src/blurbs.h b/src/blurbs.h
index 2d71ed0c..4fdea0fe 100644
--- a/src/blurbs.h
+++ b/src/blurbs.h
@@ -1,7 +1,7 @@
 /* blurbs.h - warranty and conditions blurbs
-   Copyright (C) 2011-2017 Simon Josefsson
+   Copyright (C) 2011-2019 Simon Josefsson, Tim Ruehsen
 
    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.
@@ -14,11 +14,11 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #define GREETING							\
-  "Copyright (C) 2011-2017  Simon Josefsson\n"				\
+  "Copyright (C) 2011-2019  Simon Josefsson, Tim Ruehsen\n"				\
   "This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n" \
   "This is free software, and you are welcome to redistribute it\n"	\
   "under certain conditions; type `show c' for details.\n\n"
 
 #define WARRANTY							\
diff --git a/src/idn2.c b/src/idn2.c
index b13ecad5..c890d8e8 100644
--- a/src/idn2.c
+++ b/src/idn2.c
@@ -1,7 +1,7 @@
 /* idn2.c - command line interface to libidn2
-   Copyright (C) 2011-2017 Simon Josefsson
+   Copyright (C) 2011-2019 Simon Josefsson, Tim Ruehsen
 
    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.
@@ -48,11 +48,11 @@ extern // define a global const variable in C++, C doesn't need it.
 #endif
 const char version_etc_copyright[] =
   /* Do *not* mark this string for translation.  %s is a copyright
      symbol suitable for this locale, and %d is the copyright
      year.  */
-  "Copyright %s %d Simon Josefsson.";
+  "Copyright 2011-%s %d Simon Josefsson, Tim Ruehsen.";
 
 static void
 usage (int status)
 {
   if (status != EXIT_SUCCESS)
@@ -76,27 +76,28 @@ To process a string that starts with `-', for example `-foo', use `--'\n\
 to signal the end of parameters, as in `idn2 --quiet -- -foo'.\n\
 \n\
 Mandatory arguments to long options are mandatory for short options too.\n\
 "), stdout);
       fputs (_("\
-  -h, --help               Print help and exit\n\
-  -V, --version            Print version and exit\n\
+  -h, --help                Print help and exit\n\
+  -V, --version             Print version and exit\n\
 "), stdout);
       fputs (_("\
-  -d, --decode             Decode (punycode) domain name\n\
-  -l, --lookup             Lookup domain name (default)\n\
-  -r, --register           Register label\n\
+  -d, --decode              Decode (punycode) domain name\n\
+  -l, --lookup              Lookup domain name (default)\n\
+  -r, --register            Register label\n\
 "), stdout);
       fputs (_("\
-  -T, --tr46t              Enable TR46 transitional processing\n\
-  -N, --tr46nt             Enable TR46 non-transitional processing\n\
-      --no-tr46            Disable TR46 processing\n\
+  -T, --tr46t               Enable TR46 transitional processing\n\
+  -N, --tr46nt              Enable TR46 non-transitional processing\n\
+      --no-tr46             Disable TR46 processing\n\
 "), stdout);
       fputs (_("\
-      --usestd3asciirules  Enable STD3 ASCII rules\n\
-      --debug              Print debugging information\n\
-      --quiet              Silent operation\n\
+      --usestd3asciirules   Enable STD3 ASCII rules\n\
+      --no-alabelroundtrip  Disable ALabel rountrip for lookups\n\
+      --debug               Print debugging information\n\
+      --quiet               Silent operation\n\
 "), stdout);
       emit_bug_reporting_address ();
     }
   exit (status);
 }
@@ -199,11 +200,11 @@ main (int argc, char *argv[])
     return EXIT_FAILURE;
 
   if (args_info.version_given)
     {
       version_etc (stdout, "idn2", PACKAGE_NAME, VERSION,
-		   "Simon Josefsson", (char *) NULL);
+		   "Simon Josefsson, Tim Ruehsen", (char *) NULL);
       return EXIT_SUCCESS;
     }
 
   if (args_info.help_given)
     usage (EXIT_SUCCESS);
@@ -228,10 +229,13 @@ main (int argc, char *argv[])
     flags = IDN2_NO_TR46;
 
   if (flags && args_info.usestd3asciirules_given)
     flags |= IDN2_USE_STD3_ASCII_RULES;
 
+  if (flags && args_info.no_alabelroundtrip_given)
+    flags |= IDN2_NO_ALABEL_ROUNDTRIP;
+
   for (cmdn = 0; cmdn < args_info.inputs_num; cmdn++)
     process_input (args_info.inputs[cmdn], flags | IDN2_NFC_INPUT);
 
   if (!cmdn)
     {
diff --git a/src/idn2.ggo b/src/idn2.ggo
index 3732cb5d..04a5360d 100644
--- a/src/idn2.ggo
+++ b/src/idn2.ggo
@@ -18,7 +18,8 @@ option "lookup" l "Lookup domain name (default)" no
 option "register" r "Register label" no
 option "tr46t" T "Enable TR46 transitional processing" flag off
 option "tr46nt" N "Enable TR46 non-transitional processing" flag off
 option "no-tr46" - "Disable TR46 processing" flag off
 option "usestd3asciirules" - "Enable STD3 ASCII rules" flag off
+option "no-alabelroundtrip" - "Disable ALabel roundtrip for lookups" flag off
 option "debug" - "Print debugging information" flag off
 option "quiet" - "Silent operation" flag off

Vulnerable code:  * @IDN2_ALABEL_ROUNDTRIP: Perform optional IDNA2008 lookup roundtrip check (not implemented yet).
 * @IDN2_NO_TR46: Disable Unicode TR46 processing (default).
 * @IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional processing.
    IDN2_NO_TR46 = 64
  int rc;
  size_t tmpl;

  if (_idn2_ascii_p (src, srclen))
    {
      if (flags & IDN2_ALABEL_ROUNDTRIP)
	/* FIXME implement this MAY:

	   If the input to this procedure appears to be an A-label
	   (i.e., it starts in "xn--", interpreted
	   case-insensitively), the lookup application MAY attempt to
	   convert it to a U-label, first ensuring that the A-label is
	   entirely in lowercase (converting it to lowercase if
	   necessary), and apply the tests of Section 5.4 and the
	   conversion of Section 5.5 to that form. */
	return IDN2_INVALID_FLAGS;
    return rc;
	  free(p);
	  return rc;
    return rc;
  return IDN2_OK;
 * testing (not implemented yet).
 * Unicode TR46 non-transitional processing.  Multiple flags may be
 * specified by binary or:ing them together.
 * Pass %IDN2_ALABEL_ROUNDTRIP in @flags to convert any input A-labels
 * to U-labels and perform additional testing.  Pass
 * %IDN2_TRANSITIONAL to enable Unicode TR46 transitional processing,
 * processing.  Multiple flags may be specified by binary or:ing them
 * together, for example %IDN2_ALABEL_ROUNDTRIP |
 * %IDN2_NONTRANSITIONAL.  The %IDN2_NFC_INPUT in @flags is always
 * enabled in this function.
   Copyright (C) 2011-2017 Simon Josefsson
  "Copyright (C) 2011-2017  Simon Josefsson\n"				\
   Copyright (C) 2011-2017 Simon Josefsson
  "Copyright %s %d Simon Josefsson.";
  -h, --help               Print help and exit\n\
  -V, --version            Print version and exit\n\
  -d, --decode             Decode (punycode) domain name\n\
  -l, --lookup             Lookup domain name (default)\n\
  -r, --register           Register label\n\
  -T, --tr46t              Enable TR46 transitional processing\n\
  -N, --tr46nt             Enable TR46 non-transitional processing\n\
      --no-tr46            Disable TR46 processing\n\
      --usestd3asciirules  Enable STD3 ASCII rules\n\
      --debug              Print debugging information\n\
      --quiet              Silent operation\n\
		   "Simon Josefsson", (char *) NULL);
Fixed code:     case IDN2_ALABEL_ROUNDTRIP_FAILED: return _("Alabel roundtrip failed");
    case IDN2_ALABEL_ROUNDTRIP_FAILED: return ERR2STR (IDN2_ALABEL_ROUNDTRIP_FAILED);
 * @IDN2_ALABEL_ROUNDTRIP: Perform optional IDNA2008 lookup roundtrip check (default).
 * @IDN2_NO_ALABEL_ROUNDTRIP: Disable ALabel lookup roundtrip check.
 * @IDN2_NO_TR46: Disable Unicode TR46 processing.
 * @IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional processing (default).
    IDN2_NO_TR46 = 64,
    IDN2_NO_ALABEL_ROUNDTRIP = 128
 * @IDN2_ALABEL_ROUNDTRIP_FAILED: ALabel -> Ulabel -> ALabel result differs from input.
    IDN2_ALABEL_ROUNDTRIP_FAILED = -314,
  if (((*flags) & IDN2_ALABEL_ROUNDTRIP) && ((*flags) & IDN2_NO_ALABEL_ROUNDTRIP))
    return IDN2_INVALID_FLAGS;

  const uint8_t *src_org = NULL;
  uint8_t *src_allocated = NULL;
  int rc, check_roundtrip = 0;
  size_t tmpl, srclen_org = 0;
  uint32_t label_u32[IDN2_LABEL_MAX_LENGTH];
  size_t label32_len = IDN2_LABEL_MAX_LENGTH;

  if (_idn2_ascii_p (src, srclen)) {
    if (!(flags & IDN2_NO_ALABEL_ROUNDTRIP) && srclen >= 4 && memcmp (src, "xn--", 4) == 0) {
      /*
	 If the input to this procedure appears to be an A-label
	 (i.e., it starts in "xn--", interpreted
	 case-insensitively), the lookup application MAY attempt to
	 convert it to a U-label, first ensuring that the A-label is
	 entirely in lowercase (converting it to lowercase if
	 necessary), and apply the tests of Section 5.4 and the
	 conversion of Section 5.5 to that form. */
      rc = _idn2_punycode_decode (srclen - 4, (char *) src + 4, &label32_len, label_u32);
      if (rc)
	return rc;
      check_roundtrip = 1;
      src_org = src;
      srclen_org = srclen;

      srclen = IDN2_LABEL_MAX_LENGTH;
      src = src_allocated = u32_to_u8 (label_u32, label32_len, NULL, &srclen);
      if (!src) {
	if (errno == ENOMEM)
	  return IDN2_MALLOC;
	return IDN2_ENCODING_ERROR;
      }
    } else {
  }
    goto out;
	  free (p);
	  goto out;
    goto out;

  if (check_roundtrip)
    {
      if (srclen_org != *dstlen || memcmp (src_org, dst, srclen_org))
      {
        rc = IDN2_ALABEL_ROUNDTRIP_FAILED;
	goto out;
      }
    }

  rc = IDN2_OK;

out:
  free (src_allocated);
  return rc;
 *
 * testing. This is default since version 2.2.
 * To switch this behavior off, pass IDN2_NO_ALABEL_ROUNDTRIP
 *
 * Unicode TR46 non-transitional processing.
 *
 * Multiple flags may be specified by binary or:ing them together.
 * Pass %IDN2_ALABEL_ROUNDTRIP in @flags to
 * convert any input A-labels to U-labels and perform additional
 * testing. This is default since version 2.2.
 * To switch this behavior off, pass IDN2_NO_ALABEL_ROUNDTRIP
 *
 * Pass %IDN2_TRANSITIONAL to enable Unicode TR46 transitional processing,
 * processing.
 *
 * Multiple flags may be specified by binary or:ing them together, for
 * example %IDN2_ALABEL_ROUNDTRIP | %IDN2_NONTRANSITIONAL.
 *
 * The %IDN2_NFC_INPUT in @flags is always enabled in this function.
   Copyright (C) 2011-2019 Simon Josefsson, Tim Ruehsen
  "Copyright (C) 2011-2019  Simon Josefsson, Tim Ruehsen\n"				\
   Copyright (C) 2011-2019 Simon Josefsson, Tim Ruehsen
  "Copyright 2011-%s %d Simon Josefsson, Tim Ruehsen.";
  -h, --help                Print help and exit\n\
  -V, --version             Print version and exit\n\
  -d, --decode              Decode (punycode) domain name\n\
  -l, --lookup              Lookup domain name (default)\n\
  -r, --register            Register label\n\
  -T, --tr46t               Enable TR46 transitional processing\n\
  -N, --tr46nt              Enable TR46 non-transitional processing\n\
      --no-tr46             Disable TR46 processing\n\
      --usestd3asciirules   Enable STD3 ASCII rules\n\
      --no-alabelroundtrip  Disable ALabel rountrip for lookups\n\
      --debug               Print debugging information\n\
      --quiet               Silent operation\n\
		   "Simon Josefsson, Tim Ruehsen", (char *) NULL);
  if (flags && args_info.no_alabelroundtrip_given)
    flags |= IDN2_NO_ALABEL_ROUNDTRIP;

option "no-alabelroundtrip" - "Disable ALabel roundtrip for lookups" flag off