summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-23 13:12:08 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-23 15:02:21 +0100
commit86392e5115bb8629b67dbd535359bbc6df30460d (patch)
tree99eb821d060a081ef03a0938e30fb41aaa827fe0
parentf8ca14a1b0b6164be9ff03a3e69f77f0777b3d6d (diff)
downloadgnutls-86392e5115bb8629b67dbd535359bbc6df30460d.tar.gz
IDNA code re-organization
That introduces the internal function gnutls_idna_map(), which utilizes libidn and libunistring to convert hostnames to IDNA ACE form.
-rw-r--r--lib/ext/server_name.c81
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/str-unicode.c72
-rw-r--r--lib/str.h18
-rw-r--r--lib/x509.c15
-rw-r--r--lib/x509/Makefile.am1
-rw-r--r--lib/x509/email-verify.c34
-rw-r--r--lib/x509/gnutls-idna.h52
-rw-r--r--lib/x509/hostname-verify.c37
-rw-r--r--lib/x509/output.c15
-rw-r--r--lib/x509/pkcs7-output.c1
11 files changed, 168 insertions, 159 deletions
diff --git a/lib/ext/server_name.c b/lib/ext/server_name.c
index 89118a6d4e..ba286112b3 100644
--- a/lib/ext/server_name.c
+++ b/lib/ext/server_name.c
@@ -24,11 +24,8 @@
#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;
}
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index be584c5c08..25de038dbd 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -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;
};
diff --git a/lib/str-unicode.c b/lib/str-unicode.c
index f77b2d443f..f8d6880e63 100644
--- a/lib/str-unicode.c
+++ b/lib/str-unicode.c
@@ -26,6 +26,10 @@
#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 */
diff --git a/lib/str.h b/lib/str.h
index 7800eec2eb..ae50a77387 100644
--- 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);
diff --git a/lib/x509.c b/lib/x509.c
index 17b3b0f385..b2cda15832 100644
--- a/lib/x509.c
+++ b/lib/x509.c
@@ -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;
}
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am
index dc7e827cb8..afcc230f3f 100644
--- a/lib/x509/Makefile.am
+++ b/lib/x509/Makefile.am
@@ -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 \
diff --git a/lib/x509/email-verify.c b/lib/x509/email-verify.c
index e6a3b1773c..a96d5ca192 100644
--- a/lib/x509/email-verify.c
+++ b/lib/x509/email-verify.c
@@ -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
index 291dddccd4..0000000000
--- a/lib/x509/gnutls-idna.h
+++ /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
diff --git a/lib/x509/hostname-verify.c b/lib/x509/hostname-verify.c
index fcbb987e64..1491b0ac52 100644
--- a/lib/x509/hostname-verify.c
+++ b/lib/x509/hostname-verify.c
@@ -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;
}
diff --git a/lib/x509/output.c b/lib/x509/output.c
index bd4d3dba8c..a6b0b64e8a 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -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));
diff --git a/lib/x509/pkcs7-output.c b/lib/x509/pkcs7-output.c
index 3042720108..26cdc1cb3e 100644
--- a/lib/x509/pkcs7-output.c
+++ b/lib/x509/pkcs7-output.c
@@ -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