CVE-2019-12290 (C, published 2019-10-22T16:15Z)
Description: 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.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-20 \u2014 Improper Input Validation
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.
Repository: https://gitlab.com/libidn/libidn2
Files changed:
lib/error.c
lib/idn2.h.in
lib/lookup.c
src/blurbs.h
src/idn2.c
src/idn2.ggo
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.


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