diff options
-rw-r--r-- | lib/ext/server_name.c | 81 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 | ||||
-rw-r--r-- | lib/str-unicode.c | 72 | ||||
-rw-r--r-- | lib/str.h | 18 | ||||
-rw-r--r-- | lib/x509.c | 15 | ||||
-rw-r--r-- | lib/x509/Makefile.am | 1 | ||||
-rw-r--r-- | lib/x509/email-verify.c | 34 | ||||
-rw-r--r-- | lib/x509/gnutls-idna.h | 52 | ||||
-rw-r--r-- | lib/x509/hostname-verify.c | 37 | ||||
-rw-r--r-- | lib/x509/output.c | 15 | ||||
-rw-r--r-- | lib/x509/pkcs7-output.c | 1 |
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 */ @@ -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 |