]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
IDNA code re-organization
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 23 Nov 2016 12:12:08 +0000 (13:12 +0100)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 23 Nov 2016 14:02:21 +0000 (15:02 +0100)
That introduces the internal function gnutls_idna_map(), which
utilizes libidn and libunistring to convert hostnames to IDNA ACE
form.

lib/ext/server_name.c
lib/libgnutls.map
lib/str-unicode.c
lib/str.h
lib/x509.c
lib/x509/Makefile.am
lib/x509/email-verify.c
lib/x509/gnutls-idna.h [deleted file]
lib/x509/hostname-verify.c
lib/x509/output.c
lib/x509/pkcs7-output.c

index 89118a6d4e59bd3628022b0a152dcfcfbb0c6418..ba286112b37a9c9ae71995254007cba0499c7e8c 100644 (file)
 #include "auth.h"
 #include "errors.h"
 #include "num.h"
+#include "str.h"
 #include <ext/server_name.h>
-#ifdef HAVE_LIBIDN
-# include <idna.h>
-# include <idn-free.h>
-#endif
 
 static int _gnutls_server_name_recv_params(gnutls_session_t session,
                                           const uint8_t * data,
@@ -297,12 +294,8 @@ gnutls_server_name_get(gnutls_session_t session, void *data,
        char *_data = data;
        server_name_ext_st *priv;
        int ret;
-#ifdef HAVE_LIBIDN
-       int rc;
-       char *idn_name = NULL;
-#endif
+       gnutls_datum_t idn_name = {NULL,0};
        extension_priv_data_t epriv;
-       gnutls_datum_t name;
 
        if (session->security_parameters.entity == GNUTLS_CLIENT) {
                gnutls_assert();
@@ -326,62 +319,32 @@ gnutls_server_name_get(gnutls_session_t session, void *data,
 
        *type = priv->server_names[indx].type;
 
-#ifdef HAVE_LIBIDN
-       rc = idna_to_ascii_8z ((char*)priv->server_names[indx].name, &idn_name, IDNA_ALLOW_UNASSIGNED);
-       if (rc != IDNA_SUCCESS) {
-                _gnutls_debug_log("unable to convert name %s to IDNA format: %s\n", (char*)priv->server_names[indx].name, idna_strerror(rc));
+       ret = gnutls_idna_map((char*)priv->server_names[indx].name, priv->server_names[indx].name_length, &idn_name, 0);
+       if (ret < 0) {
+                _gnutls_debug_log("unable to convert name %s to IDNA2008 format\n", (char*)priv->server_names[indx].name);
                 return GNUTLS_E_IDNA_ERROR;
        }
-       name.data = (unsigned char*)idn_name;
-       name.size = strlen(idn_name);
-#else
-       name.data = priv->server_names[indx].name;
-       name.size = priv->server_names[indx].name_length;
-#endif
 
        if (*data_length >      /* greater since we need one extra byte for the null */
-           name.size) {
-               *data_length = name.size;
-               memcpy(data, name.data, *data_length);
+           idn_name.size) {
+               *data_length = idn_name.size;
+               memcpy(data, idn_name.data, *data_length);
 
                if (*type == GNUTLS_NAME_DNS)   /* null terminate */
                        _data[(*data_length)] = 0;
 
        } else {
-               *data_length = name.size + 1;
+               *data_length = idn_name.size + 1;
                ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
                goto cleanup;
        }
 
        ret = 0;
  cleanup:
-#ifdef HAVE_LIBIDN
-       idn_free(idn_name);
-#endif
+       gnutls_free(idn_name.data);
        return ret;
 }
 
-#ifdef HAVE_LIBIDN
-static int l_idna_to_ascii (const char *_name, unsigned length, char **output)
-{
-       char *name;
-       int rc;
-
-       name = gnutls_malloc(length+1);
-       if (name == NULL)
-               return IDNA_MALLOC_ERROR;
-
-       memcpy(name, _name, length);
-       name[length] = 0;
-
-       rc = idna_to_ascii_8z (name, output, IDNA_ALLOW_UNASSIGNED);
-
-       gnutls_free(name);
-
-       return rc;
-}
-#endif
-
 /* This does not do any conversion not perform any check */
 int
 _gnutls_server_name_set_raw(gnutls_session_t session,
@@ -467,8 +430,8 @@ gnutls_server_name_set(gnutls_session_t session,
                       gnutls_server_name_type_t type,
                       const void *name, size_t name_length)
 {
-       int ret, rc;
-       char *idn_name = NULL;
+       int ret;
+       gnutls_datum_t idn_name = {NULL,0};
 
        if (session->security_parameters.entity == GNUTLS_SERVER) {
                gnutls_assert();
@@ -480,20 +443,18 @@ gnutls_server_name_set(gnutls_session_t session,
                return 0;
        }
 
-#ifdef HAVE_LIBIDN
-       rc = l_idna_to_ascii (name, name_length, &idn_name);
-       if (rc != IDNA_SUCCESS) {
-                _gnutls_debug_log("unable to convert name %s to IDNA format: %s\n", (char*)name, idna_strerror(rc));
-                return GNUTLS_E_IDNA_ERROR;
+       ret = gnutls_idna_map(name, name_length, &idn_name, 0);
+       if (ret < 0) {
+                _gnutls_debug_log("unable to convert name %s to IDNA2008 format\n", (char*)name);
+                return ret;
        }
-       name = idn_name;
-       name_length = strlen(idn_name);
-#endif
+
+       name = idn_name.data;
+       name_length = idn_name.size;
 
        ret = _gnutls_server_name_set_raw(session, type, name, name_length);
-#ifdef HAVE_LIBIDN
-       idn_free(idn_name);
-#endif
+       gnutls_free(idn_name.data);
+
        return ret;
 }
 
index be584c5c08f5a626d47f57a364a5151a8282edea..25de038dbd753ee370ba420d01a6b8ebdf70af85 100644 (file)
@@ -1198,4 +1198,5 @@ GNUTLS_PRIVATE_3_4 {
        # Internal symbols needed by tests/name-constraints-merge:
        _gnutls_x509_name_constraints_merge;
        _gnutls_server_name_set_raw;
+       gnutls_idna_map;
 };
index f77b2d443f2b4a07f3a41a17e17cb46cf070a566..f8d6880e634076b51291c5365032d18b912259ff 100644 (file)
 #include <uninorm.h>
 #include <unistr.h>
 #include <unictype.h>
+#ifdef HAVE_LIBIDN
+# include <idna.h>
+# include <idn-free.h>
+#endif
 
 /**
  * gnutls_utf8_password_normalize:
@@ -140,3 +144,71 @@ int gnutls_utf8_password_normalize(const unsigned char *password, unsigned passw
        gnutls_free(nrmu8);
        return ret;
 }
+
+#ifdef HAVE_LIBIDN
+/*-
+ * gnutls_idna_map:
+ * @input: contain the UTF-8 formatted domain name
+ * @ilen: the length of the provided string
+ * @out: the result in an null-terminated allocated string
+ * @flags: should be zero
+ *
+ * This function will convert the provided UTF-8 domain name, to
+ * its IDNA2003 mapping.
+ *
+ * If GnuTLS is compiled without libidn2 support, then this function
+ * will return %GNUTLS_E_UNIMPLEMENTED_FEATURE.
+ *
+ * Returns: %GNUTLS_E_INVALID_UTF8_STRING on invalid UTF-8 data, or 0 on success.
+ *
+ * Since: 3.5.7
+ -*/
+int gnutls_idna_map(const char *input, unsigned ilen, gnutls_datum_t *out, unsigned flags)
+{
+       char *idna = NULL;
+       int rc, ret;
+       gnutls_datum_t istr;
+
+       if (ilen == 0) {
+               out->data = (uint8_t*)gnutls_strdup("");
+               out->size = 0;
+               if (out->data == NULL)
+                       return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+               return 0;
+       }
+
+       ret = _gnutls_set_strdatum(&istr, input, ilen);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       rc = idna_to_ascii_8z((char*)istr.data, &idna, 0);
+       if (rc != IDNA_SUCCESS) {
+               gnutls_assert();
+               _gnutls_debug_log("unable to convert name '%s' to IDNA format: %s\n", istr.data, idna_strerror(rc));
+               ret = GNUTLS_E_INVALID_UTF8_STRING;
+               goto fail;
+       }
+
+       if (gnutls_malloc != malloc) {
+               ret = _gnutls_set_strdatum(out, idna, strlen(idna));
+       } else  {
+               out->data = (unsigned char*)idna;
+               out->size = strlen(idna);
+               idna = NULL;
+               ret = 0;
+       }
+ fail:
+       idn_free(idna);
+       gnutls_free(istr.data);
+       return ret;
+}
+#else
+
+# undef gnutls_idna_map
+int gnutls_idna_map(const char *input, unsigned ilen, gnutls_datum_t *out, unsigned flags)
+{
+       return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
+}
+#endif /* HAVE_LIBIDN2 */
index 7800eec2eba187167392eb86d9466f82ae00fbb8..ae50a773876ca4e05b368cfdfc434d3d5b799576 100644 (file)
--- a/lib/str.h
+++ b/lib/str.h
@@ -25,6 +25,7 @@
 
 #include <config.h>
 #include "gnutls_int.h"
+#include "errors.h"
 #include <datum.h>
 
 #ifdef HAVE_DCGETTEXT
@@ -43,6 +44,23 @@ int gnutls_utf8_password_normalize(const uint8_t *password, unsigned password_le
        gnutls_utf8_password_normalize((unsigned char*)p, plen, out, \
                ignore_errs?(GNUTLS_UTF8_IGNORE_ERRS):0)
 
+#ifndef HAVE_LIBIDN
+inline static
+int _gnutls_idna_map(const char *input, unsigned ilen, gnutls_datum_t *out, unsigned flags)
+{
+       out->data = gnutls_malloc(ilen+1);
+       if (out->data == NULL)
+               return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+       out->size = ilen;
+       memcpy(out->data, input, ilen);
+       out->data[ilen] = 0;
+       return 0;
+}
+# define gnutls_idna_map _gnutls_idna_map
+#else
+int gnutls_idna_map(const char * input, unsigned ilen, gnutls_datum_t *out, unsigned flags);
+#endif
+
 void _gnutls_str_cpy(char *dest, size_t dest_tot_size, const char *src);
 void _gnutls_mem_cpy(char *dest, size_t dest_tot_size, const char *src,
                     size_t src_size);
index 17b3b0f38542c63d9caa0711b03efae382614814..b2cda15832469d4e0a7b2f2170e3731a81613f77 100644 (file)
@@ -45,7 +45,6 @@
 #include "x509/x509_int.h"
 #include <str_array.h>
 #include <gnutls/x509.h>
-#include "gnutls-idna.h"
 #include "read-file.h"
 #include "system-keys.h"
 #include "urls.h"
@@ -406,19 +405,19 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session,
 
 static int str_array_append_idna(gnutls_str_array_t * head, const char *name, size_t size)
 {
-       int rc, ret;
-       char *a_hostname;
+       int ret;
+       gnutls_datum_t ahost;
 
        /* convert the provided hostname to ACE-Labels domain. */
-       rc = idna_to_ascii_8z(name, &a_hostname, 0);
-       if (rc != IDNA_SUCCESS) {
-               _gnutls_debug_log("unable to convert hostname %s to IDNA format: %s\n", name, idna_strerror (rc));
+       ret = gnutls_idna_map(name, size, &ahost, 0);
+       if (ret < 0) {
+               _gnutls_debug_log("unable to convert hostname %s to IDNA format\n", name);
                /* insert the raw name */
                return _gnutls_str_array_append(head, name, size);
        }
 
-       ret = _gnutls_str_array_append(head, a_hostname, strlen(a_hostname));
-       idn_free(a_hostname);
+       ret = _gnutls_str_array_append(head, (char*)ahost.data, ahost.size);
+       gnutls_free(ahost.data);
 
        return ret;
 }
index dc7e827cb876c3cedb629766842dab2bec9bed9f..afcc230f3f1c90db8fdae1c9de4a53ed67f65e34 100644 (file)
@@ -36,7 +36,6 @@ libgnutls_x509_la_SOURCES =   \
        common.c key_encode.c   \
        common.h key_decode.c   \
        time.c                  \
-       gnutls-idna.h           \
        crl.c                   \
        crl_write.c             \
        crq.c                   \
index e6a3b1773c1f7959f6969f6c519d3e8b58bba1ff..a96d5ca1927c61b793bf586b65a835f53e490b8e 100644 (file)
@@ -25,7 +25,6 @@
 #include <common.h>
 #include "errors.h"
 #include <system.h>
-#include <gnutls-idna.h>
 
 static int has_embedded_null(const char *str, unsigned size)
 {
@@ -52,16 +51,19 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
        char rfc822name[MAX_CN];
        size_t rfc822namesize;
        int found_rfc822name = 0;
-       int ret = 0, rc;
+       int ret = 0;
        int i = 0;
        char *a_email;
        char *a_rfc822name;
+       gnutls_datum_t out;
 
        /* convert the provided email to ACE-Labels domain. */
-       rc = idna_to_ascii_8z (email, &a_email, 0);
-       if (rc != IDNA_SUCCESS) {
-               _gnutls_debug_log("unable to convert email %s to IDNA format: %s\n", email, idna_strerror (rc));
+       ret = gnutls_idna_map(email, strlen(email), &out, 0);
+       if (ret < 0) {
+               _gnutls_debug_log("unable to convert email %s to IDNA format\n", email);
                a_email = (char*)email;
+       } else {
+               a_email = (char*)out.data;
        }
 
        /* try matching against:
@@ -92,14 +94,16 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
                                continue;
                        }
 
-                       rc = idna_to_ascii_8z (rfc822name, &a_rfc822name, 0);
-                       if (rc != IDNA_SUCCESS) {
-                               _gnutls_debug_log("unable to convert rfc822name %s to IDNA format: %s\n", rfc822name, idna_strerror (rc));
+                       ret = gnutls_idna_map(rfc822name, rfc822namesize, &out, 0);
+                       if (ret < 0) {
+                               _gnutls_debug_log("unable to convert rfc822name %s to IDNA format\n", rfc822name);
                                continue;
                        }
 
+                       a_rfc822name = (char*)out.data;
+
                        ret = _gnutls_hostname_compare(a_rfc822name, strlen(a_rfc822name), a_email, GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
-                       idn_free(a_rfc822name);
+                       gnutls_free(a_rfc822name);
 
                        if (ret != 0) {
                                ret = 1;
@@ -138,16 +142,18 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
                        goto cleanup;
                }
 
-               rc = idna_to_ascii_8z (rfc822name, &a_rfc822name, 0);
-               if (rc != IDNA_SUCCESS) {
-                       _gnutls_debug_log("unable to convert EMAIL %s to IDNA format: %s\n", rfc822name, idna_strerror (rc));
+               ret = gnutls_idna_map (rfc822name, rfc822namesize, &out, 0);
+               if (ret < 0) {
+                       _gnutls_debug_log("unable to convert EMAIL %s to IDNA format\n", rfc822name);
                        ret = 0;
                        goto cleanup;
                }
 
+               a_rfc822name = (char*)out.data;
+
                ret = _gnutls_hostname_compare(a_rfc822name, strlen(a_rfc822name), a_email, GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
 
-               idn_free(a_rfc822name);
+               gnutls_free(a_rfc822name);
 
                if (ret != 0) {
                        ret = 1;
@@ -160,7 +166,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
        ret = 0;
  cleanup:
        if (a_email != email) {
-               idn_free(a_email);
+               gnutls_free(a_email);
        }
        return ret;
 }
diff --git a/lib/x509/gnutls-idna.h b/lib/x509/gnutls-idna.h
deleted file mode 100644 (file)
index 291dddc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 Red Hat
- *
- * Author: Nikos Mavrogiannopoulos
- *
- * This file is part of GnuTLS.
- *
- * The GnuTLS 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 library 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 _GNUTLS_IDNA_H
-# define _GNUTLS_IDNA_H
-
-#include <config.h>
-
-#ifdef HAVE_LIBIDN
-# include <idna.h>
-# include <idn-free.h>
-
-#else /* #ifndef HAVE_LIBIDN */
-
-#define IDNA_SUCCESS 0
-
-static inline
-int idna_to_ascii_8z(const char * input, char ** output, int flags)
-{
-       *output = (char*)input;
-       return 0;
-}
-
-#define idn_free(x)
-
-static inline
-const char *idna_strerror(int ret)
-{
-       return "";
-}
-#endif
-
-#endif
index fcbb987e6459a65faa68845b3d91a824491188c6..1491b0ac52d4b53b9948f70f6f09895adacc9c0d 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2003-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2003-2016 Free Software Foundation, Inc.
+ * Copyright (C) 2015-2016 Red Hat, Inc.
  * Copyright (C) 2002 Andrew McDonald
  *
  * This file is part of GnuTLS.
@@ -25,7 +26,6 @@
 #include <common.h>
 #include "errors.h"
 #include <system.h>
-#include <gnutls-idna.h>
 
 /**
  * gnutls_x509_crt_check_hostname:
@@ -123,12 +123,13 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
        char dnsname[MAX_CN];
        size_t dnsnamesize;
        int found_dnsname = 0;
-       int ret = 0, rc;
+       int ret = 0;
        int i = 0;
        struct in_addr ipv4;
        char *p = NULL;
        char *a_hostname;
        char *a_dnsname;
+       gnutls_datum_t out;
 
        /* check whether @hostname is an ip address */
        if ((p=strchr(hostname, ':')) != NULL || inet_aton(hostname, &ipv4) != 0) {
@@ -156,10 +157,12 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
 
  hostname_fallback:
        /* convert the provided hostname to ACE-Labels domain. */
-       rc = idna_to_ascii_8z (hostname, &a_hostname, 0);
-       if (rc != IDNA_SUCCESS) {
-               _gnutls_debug_log("unable to convert hostname %s to IDNA format: %s\n", hostname, idna_strerror (rc));
+       ret = gnutls_idna_map (hostname, strlen(hostname), &out, 0);
+       if (ret < 0) {
+               _gnutls_debug_log("unable to convert hostname %s to IDNA format\n", hostname);
                a_hostname = (char*)hostname;
+       } else {
+               a_hostname = (char*)out.data;
        }
 
        /* try matching against:
@@ -192,14 +195,16 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
                                continue;
                        }
 
-                       rc = idna_to_ascii_8z (dnsname, &a_dnsname, 0);
-                       if (rc != IDNA_SUCCESS) {
-                               _gnutls_debug_log("unable to convert dnsname %s to IDNA format: %s\n", dnsname, idna_strerror (rc));
+                       ret = gnutls_idna_map (dnsname, dnsnamesize, &out, 0);
+                       if (ret < 0) {
+                               _gnutls_debug_log("unable to convert dnsname %s to IDNA format\n", dnsname);
                                continue;
                        }
 
+                       a_dnsname = (char*)out.data;
+
                        ret = _gnutls_hostname_compare(a_dnsname, strlen(a_dnsname), a_hostname, flags);
-                       idn_free(a_dnsname);
+                       gnutls_free(a_dnsname);
 
                        if (ret != 0) {
                                ret = 1;
@@ -241,16 +246,18 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
                        goto cleanup;
                }
 
-               rc = idna_to_ascii_8z (dnsname, &a_dnsname, 0);
-               if (rc != IDNA_SUCCESS) {
-                       _gnutls_debug_log("unable to convert CN %s to IDNA format: %s\n", dnsname, idna_strerror (rc));
+               ret = gnutls_idna_map (dnsname, dnsnamesize, &out, 0);
+               if (ret < 0) {
+                       _gnutls_debug_log("unable to convert CN %s to IDNA format\n", dnsname);
                        ret = 0;
                        goto cleanup;
                }
 
+               a_dnsname = (char*)out.data;
+
                ret = _gnutls_hostname_compare(a_dnsname, strlen(a_dnsname), a_hostname, flags);
 
-               idn_free(a_dnsname);
+               gnutls_free(a_dnsname);
 
                if (ret != 0) {
                        ret = 1;
@@ -263,7 +270,7 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
        ret = 0;
  cleanup:
        if (a_hostname != hostname) {
-               idn_free(a_hostname);
+               gnutls_free(a_hostname);
        }
        return ret;
 }
index bd4d3dba8c61ec6a54f867f481b6ec440846c8d8..a6b0b64e8a44c40646f2b002f83ac7dc4d05a563 100644 (file)
@@ -32,7 +32,6 @@
 #include "errors.h"
 #include <extras/randomart.h>
 #include <c-ctype.h>
-#include <gnutls-idna.h>
 #include "extensions.h"
 #include "ip.h"
 
@@ -52,6 +51,7 @@ unsigned non_ascii = 0;
 #ifdef HAVE_LIBIDN
 unsigned i;
 #endif
+int ret;
 
        if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_OTHERNAME_XMPP
             || type == GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
@@ -76,16 +76,15 @@ unsigned i;
 #endif
 
                if (non_ascii != 0) {
-                       char *s;
-                       int rc;
+                       gnutls_datum_t out;
 
-                       rc = idna_to_ascii_8z((char*)name->data, &s, 0);
-                       if (rc == IDNA_SUCCESS) {
-                               addf(str,  _("%sDNSname: %.*s (%s)\n"), prefix, name->size, NON_NULL(name->data), s);
-                               idn_free(s);
-                       } else {
+                       ret = gnutls_idna_map((char*)name->data, name->size, &out, 0);
+                       if (ret < 0) {
                                adds(str, _("note: DNSname is not in UTF-8.\n"));
                                addf(str,  _("%sDNSname: %.*s\n"), prefix, name->size, NON_NULL(name->data));
+                       } else {
+                               addf(str,  _("%sDNSname: %.*s (%s)\n"), prefix, name->size, NON_NULL(name->data), (char*)out.data);
+                               gnutls_free(out.data);
                        }
                } else {
                        addf(str,  _("%sDNSname: %.*s\n"), prefix, name->size, NON_NULL(name->data));
index 30427201087394b5fe42ca20779167d315ccdb75..26cdc1cb3e7bae77ac528af45300b3d7fec2d2c0 100644 (file)
@@ -28,7 +28,6 @@
 #include "errors.h"
 #include <extras/randomart.h>
 #include <pkcs7_int.h>
-#include <gnutls-idna.h>
 
 #define addf _gnutls_buffer_append_printf
 #define adds _gnutls_buffer_append_str