Blame SOURCES/bind-9.11-rh1679307.patch

89a891
From 88cf9dec060e8c3f1705a4e41a30e283bc3c8b1b Mon Sep 17 00:00:00 2001
89a891
From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= <michal@isc.org>
89a891
Date: Tue, 10 Jul 2018 14:34:35 +0200
89a891
Subject: [PATCH] Improve error handling in idn_ace_to_locale()
89a891
89a891
While idn2_to_unicode_8zlz() takes a 'flags' argument, it is ignored and
89a891
thus cannot be used to perform IDN checks on the output string.
89a891
89a891
The bug in libidn2 versions before 2.0.5 was not that a call to
89a891
idn2_to_unicode_8zlz() with certain flags set did not cause IDN checks
89a891
to be performed.  The bug was that idn2_to_unicode_8zlz() did not check
89a891
whether a conversion can be performed between UTF-8 and the current
89a891
locale's character encoding.  In other words, with libidn2 version
89a891
2.0.5+, if the current locale's character encoding is ASCII, then
89a891
idn2_to_unicode_8zlz() will fail when it is passed any Punycode string
89a891
which decodes to a non-ASCII string, even if it is a valid IDNA2008
89a891
name.
89a891
89a891
Rework idn_ace_to_locale() so that invalid IDNA2008 names are properly
89a891
and consistently detected for all libidn2 versions and locales.
89a891
89a891
Update the "idna" system test accordingly.  Add checks for processing a
89a891
server response containing Punycode which decodes to an invalid IDNA2008
89a891
name.  Fix invalid subtest description.
89a891
89a891
(cherry picked from commit 7fe0f00a3bf31dc26ee3dc8777e3076546b83990)
89a891
(cherry picked from commit 4fdee34a0b0ad142182914327a1bc53144b90ed1)
89a891
---
89a891
 bin/dig/dighost.c              | 72 ++++++++++++++++++++++++-------
89a891
 bin/tests/system/idna/tests.sh | 77 +++++++++++-----------------------
89a891
 2 files changed, 82 insertions(+), 67 deletions(-)
89a891
89a891
diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
89a891
index d46379ddc2..26528af3cc 100644
89a891
--- a/bin/dig/dighost.c
89a891
+++ b/bin/dig/dighost.c
89a891
@@ -4812,26 +4812,70 @@ idn_locale_to_ace(const char *from, char *to, size_t tolen) {
89a891
 static isc_result_t
89a891
 idn_ace_to_locale(const char *from, char *to, size_t tolen) {
89a891
 	int res;
89a891
-	char *tmp_str = NULL;
89a891
+	char *utf8_src, *tmp_str = NULL;
89a891
 
89a891
-	res = idn2_to_unicode_8zlz(from, &tmp_str,
89a891
-				   IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT);
89a891
+	/*
89a891
+	 * We need to:
89a891
+	 *
89a891
+	 *  1) check whether 'from' is a valid IDNA2008 name,
89a891
+	 *  2) if it is, output it in the current locale's character encoding.
89a891
+	 *
89a891
+	 * Unlike idn2_to_ascii_*(), idn2_to_unicode_*() functions are unable
89a891
+	 * to perform IDNA2008 validity checks.  Thus, we need to decode any
89a891
+	 * Punycode in 'from', check if the resulting name is a valid IDNA2008
89a891
+	 * name, and only once we ensure it is, output that name in the current
89a891
+	 * locale's character encoding.
89a891
+	 *
89a891
+	 * We could just use idn2_to_unicode_8zlz() + idn2_to_ascii_lz(), but
89a891
+	 * then we would not be able to universally tell invalid names and
89a891
+	 * character encoding errors apart (if the current locale uses ASCII
89a891
+	 * for character encoding, the former function would fail even for a
89a891
+	 * valid IDNA2008 name, as long as it contained any non-ASCII
89a891
+	 * character).  Thus, we need to take a longer route.
89a891
+	 *
89a891
+	 * First, convert 'from' to UTF-8, ignoring the current locale.
89a891
+	 */
89a891
+	res = idn2_to_unicode_8z8z(from, &utf8_src, 0);
89a891
+	if (res != IDN2_OK) {
89a891
+		fatal("Bad ACE string '%s' (%s), use +noidnout",
89a891
+		      from, idn2_strerror(res));
89a891
+	}
89a891
 
89a891
-	if (res == IDN2_OK) {
89a891
-		/* check the length */
89a891
-		if (strlen(tmp_str) >= tolen) {
89a891
-			debug("encoded ASC string is too long");
89a891
-			idn2_free(tmp_str);
89a891
-			return ISC_R_FAILURE;
89a891
-		}
89a891
+	/*
89a891
+	 * Then, check whether decoded 'from' is a valid IDNA2008 name.
89a891
+	 */
89a891
+	res = idn2_to_ascii_8z(utf8_src, NULL, IDN2_NONTRANSITIONAL);
89a891
+	if (res != IDN2_OK) {
89a891
+		fatal("'%s' is not a legal IDNA2008 name (%s), use +noidnout",
89a891
+		      from, idn2_strerror(res));
89a891
+	}
89a891
 
89a891
-		(void) strlcpy(to, tmp_str, tolen);
89a891
+	/*
89a891
+	 * Finally, try converting the decoded 'from' into the current locale's
89a891
+	 * character encoding.
89a891
+	 */
89a891
+	res = idn2_to_unicode_8zlz(utf8_src, &tmp_str, 0);
89a891
+	if (res != IDN2_OK) {
89a891
+		fatal("Cannot represent '%s' in the current locale (%s), "
89a891
+		      "use +noidnout or a different locale",
89a891
+		      from, idn2_strerror(res));
89a891
+	}
89a891
+
89a891
+	/*
89a891
+	 * Free the interim conversion result.
89a891
+	 */
89a891
+	idn2_free(utf8_src);
89a891
+
89a891
+	/* check the length */
89a891
+	if (strlen(tmp_str) >= tolen) {
89a891
+		debug("encoded ASC string is too long");
89a891
 		idn2_free(tmp_str);
89a891
-		return ISC_R_SUCCESS;
89a891
+		return (ISC_R_FAILURE);
89a891
 	}
89a891
 
89a891
-	fatal("'%s' is not a legal IDN name (%s), use +noidnout", from, idn2_strerror(res));
89a891
-	return ISC_R_FAILURE;
89a891
+	(void) strlcpy(to, tmp_str, tolen);
89a891
+	idn2_free(tmp_str);
89a891
+	return (ISC_R_SUCCESS);
89a891
 }
89a891
 #endif /* WITH_IDN_OUT_SUPPORT */
89a891
 #endif /* WITH_LIBIDN2 */
89a891
diff --git a/bin/tests/system/idna/tests.sh b/bin/tests/system/idna/tests.sh
89a891
index 3a9b91b442..6637bf6828 100644
89a891
--- a/bin/tests/system/idna/tests.sh
89a891
+++ b/bin/tests/system/idna/tests.sh
89a891
@@ -136,46 +136,6 @@ idna_fail() {
89a891
     status=`expr $status + $ret`
89a891
 }
89a891
 
89a891
-# Check if current version of libidn2 is >= a given version
89a891
-#
89a891
-# This requires that:
89a891
-# a) "pkg-config" exists on the system
89a891
-# b) The libidn2 installed has an associated ".pc" file
89a891
-# c) The system sort command supports "-V"
89a891
-#
89a891
-# $1 - Minimum version required
89a891
-#
89a891
-# Returns:
89a891
-# 0 - Version check is OK, libidn2 at required version or greater.
89a891
-# 1 - Version check was made, but libidn2 not at required version.
89a891
-# 2 - Could not carry out version check
89a891
-
89a891
-libidn_version_check() {
89a891
-    ret=2
89a891
-    if [ -n "`command -v pkg-config`" ]; then
89a891
-        version=`pkg-config --modversion --silence-errors libidn2`
89a891
-        if [ -n "$version" ]; then
89a891
-            # Does the sort command have a "-V" flag on this system?
89a891
-            sort -V 2>&1 > /dev/null << .
89a891
-.
89a891
-            if [ $? -eq 0 ]; then
89a891
-                # Sort -V exists.  Sort the IDN version and the minimum version
89a891
-                # required.  If the IDN version is greater than or equal to that
89a891
-                # version, it will appear last in the list.
89a891
-                last_version=`printf "%s\n" $version $1 | sort -V | tail -1`
89a891
-                if [ "$version" = "$last_version" ]; then
89a891
-                    ret=0
89a891
-                else
89a891
-                    ret=1
89a891
-                fi
89a891
-            fi
89a891
-        fi
89a891
-    fi
89a891
-
89a891
-    return $ret
89a891
-}
89a891
-
89a891
-
89a891
 # Function to check that case is preserved for an all-ASCII label.
89a891
 #
89a891
 # Without IDNA support, case-preservation is the expected behavior.
89a891
@@ -310,16 +270,7 @@ idna_enabled_test() {
89a891
     text="Checking fake A-label"
89a891
     idna_fail "$text" ""                   "xn--ahahah"
89a891
     idna_test "$text" "+noidnin +noidnout" "xn--ahahah" "xn--ahahah."
89a891
-
89a891
-    # Owing to issues with libdns, the next test will fail for versions of
89a891
-    # libidn earlier than 2.0.5.  For this reason, get the version (if
89a891
-    # available) and compare with 2.0.5.
89a891
-    libidn_version_check 2.0.5
89a891
-    if [ $? -ne 0 ]; then
89a891
-        echo_i "Skipping fake A-label +noidnin +idnout test (libidn2 version issues)"
89a891
-    else
89a891
-        idna_test "$text" "+noidnin   +idnout" "xn--ahahah" "xn--ahahah."
89a891
-    fi
89a891
+    idna_fail "$text" "+noidnin   +idnout" "xn--ahahah"
89a891
     idna_fail "$text" "+idnin   +noidnout" "xn--ahahah"
89a891
     idna_fail "$text" "+idnin     +idnout" "xn--ahahah"
89a891
 
89a891
@@ -327,7 +278,7 @@ idna_enabled_test() {
89a891
     # BIND rejects such labels: with +idnin
89a891
 
89a891
     label="xn--xflod18hstflod18hstflod18hstflod18hstflod18hstflod18-1iejjjj"
89a891
-    text="Checking punycode label shorter than minimum valid length"
89a891
+    text="Checking punycode label longer than maximum valid length"
89a891
     idna_fail "$text" ""                   "$label"
89a891
     idna_fail "$text" "+noidnin +noidnout" "$label"
89a891
     idna_fail "$text" "+noidnin   +idnout" "$label"
89a891
@@ -337,7 +288,7 @@ idna_enabled_test() {
89a891
     
89a891
 
89a891
 
89a891
-    # Tests of a valid unicode string but an invalid U-label
89a891
+    # Tests of a valid unicode string but an invalid U-label (input)
89a891
     #
89a891
     # Symbols are not valid IDNA names.
89a891
     #
89a891
@@ -347,12 +298,32 @@ idna_enabled_test() {
89a891
     #
89a891
     # The +[no]idnout options should not have any effect on the test.
89a891
 
89a891
-    text="Checking invalid U-label"
89a891
+    text="Checking invalid input U-label"
89a891
     idna_fail "$text" ""                   "🧦.com"
89a891
     idna_test "$text" "+noidnin +noidnout" "🧦.com" "\240\159\167\166.com."
89a891
     idna_test "$text" "+noidnin +idnout"   "🧦.com" "\240\159\167\166.com."
89a891
     idna_fail "$text" "+idnin   +noidnout" "🧦.com"
89a891
     idna_fail "$text" "+idnin   +idnout"   "🧦.com"
89a891
+
89a891
+    # Tests of a valid unicode string but an invalid U-label (output)
89a891
+    #
89a891
+    # Symbols are not valid IDNA names.
89a891
+    #
89a891
+    # Note that an invalid U-label is accepted even when +idnin is in effect
89a891
+    # because "xn--19g" is valid Punycode.
89a891
+    #
89a891
+    # +noidnout: "dig" should send the ACE string to the server and display the
89a891
+    #            returned qname.
89a891
+    # +idnout:   "dig" should generate an error.
89a891
+    #
89a891
+    # The +[no]idnin options should not have any effect on the test.
89a891
+
89a891
+    text="Checking invalid output U-label"
89a891
+    idna_fail "$text" ""                   "xn--19g"
89a891
+    idna_test "$text" "+noidnin +noidnout" "xn--19g" "xn--19g."
89a891
+    idna_fail "$text" "+noidnin +idnout"   "xn--19g"
89a891
+    idna_test "$text" "+idnin   +noidnout" "xn--19g" "xn--19g."
89a891
+    idna_fail "$text" "+idnin   +idnout"   "xn--19g"
89a891
 }
89a891
 
89a891
 
89a891
-- 
89a891
2.20.1
89a891