summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-08 13:00:16 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2016-11-20 12:13:26 +0100
commitd753cfdcfc7e5342a38f27dde41cf8eb530b57a3 (patch)
treebccdff920f6b2682db3c279deac939f24d60330a
parente7785d07443a85ed85347c5413acd5194e026c9e (diff)
downloadgnutls-d753cfdcfc7e5342a38f27dde41cf8eb530b57a3.tar.gz
Added function for UTF-8 normalization based on RFC7613
This introduces gnutls_utf8_password_normalize() and a dependency on libunistring.
-rw-r--r--configure.ac5
-rw-r--r--lib/Makefile.am6
-rw-r--r--lib/includes/gnutls/gnutls.h.in3
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/str-unicode.c146
-rw-r--r--lib/str.h4
6 files changed, 164 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index afc00da1b9..1960c5c2bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -293,6 +293,11 @@ AM_CONDITIONAL(HAVE_SECCOMP_TESTS, test "$seccomp_tests" = "yes")
AC_LIB_HAVE_LINKFLAGS(seccomp,, [#include <seccomp.h>
], [seccomp_init(0);])
+AC_LIB_HAVE_LINKFLAGS(unistring,, [#include <uninorm.h>
+], [u8_normalize(0, 0, 0, 0, 0);])
+
+AM_CONDITIONAL(HAVE_LIBUNISTRING, test "$HAVE_LIBUNISTRING" = "yes")
+
# check for libcrypto - used in test programs
AC_LIB_HAVE_LINKFLAGS(crypto,, [#include <openssl/evp.h>
], [EVP_CIPHER_CTX_init(NULL);])
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 94cf77107e..87d6b4ea73 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -74,7 +74,7 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c \
mem.c fingerprint.c tls-sig.c ecc.c alert.c privkey_raw.c \
system/certs.c system/threads.c system/fastopen.c system/sockets.c \
system/inet_ntop.c system/iconv.c system/vasprintf.c vasprintf.h system.c \
- str.c state.c x509.c file.c supplemental.c \
+ str.c str-unicode.c state.c x509.c file.c supplemental.c \
random.c crypto-api.c privkey.c pcert.c pubkey.c locks.c dtls.c \
system_override.c crypto-backend.c verify-tofu.c pin.c tpm.c fips.c \
safe-memfuncs.c system/inet_pton.c atfork.c atfork.h randomart.c \
@@ -137,6 +137,10 @@ if HAVE_LIBIDN
thirdparty_libadd += $(LIBIDN_LIBS)
endif
+if HAVE_LIBUNISTRING
+thirdparty_libadd += $(LTLIBUNISTRING)
+endif
+
if ENABLE_NETTLE
libgnutls_la_LIBADD += accelerated/libaccelerated.la
endif
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index e05e72b8ec..1149319c29 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -2518,6 +2518,9 @@ typedef struct gnutls_buffer_st *gnutls_buffer_t;
int gnutls_buffer_append_data(gnutls_buffer_t, const void *data, size_t data_size);
+int gnutls_utf8_password_normalize(const unsigned char *password, unsigned password_len,
+ gnutls_datum_t *out, unsigned flags);
+
/* Public extensions related functions */
typedef void *gnutls_ext_priv_data_t;
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 9b947baac6..be584c5c08 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1131,6 +1131,7 @@ GNUTLS_3_4
gnutls_x509_dn_get_str2;
gnutls_x509_crl_get_issuer_dn3;
gnutls_x509_crq_get_dn3;
+ gnutls_utf8_password_normalize;
local:
*;
};
diff --git a/lib/str-unicode.c b/lib/str-unicode.c
new file mode 100644
index 0000000000..544ce1da84
--- /dev/null
+++ b/lib/str-unicode.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * 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/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "str.h"
+
+#if defined(HAVE_LIBUNISTRING)
+#include <uninorm.h>
+#include <unistr.h>
+#include <unictype.h>
+
+/**
+ * gnutls_utf8_password_normalize:
+ * @password: contain the UTF-8 formatted password
+ * @password_len: the length of the provided password
+ * @out: the result in an null-terminated allocated string
+ * @flags: should be zero
+ *
+ * This function will convert the provided UTF-8 password according
+ * to the normalization rules in RFC7613. If GnuTLS is compiled without
+ * unicode support this function will return %GNUTLS_E_UNIMPLEMENTED_FEATURE.
+ *
+ * Returns: %GNUTLS_E_PARSING_ERROR on invalid UTF-8 data, or 0 on success.
+ **/
+int gnutls_utf8_password_normalize(const unsigned char *password, unsigned password_len,
+ gnutls_datum_t *out, unsigned flags)
+{
+ size_t plen = strlen((char*)password);
+ size_t ucs4_size = 0, nrm_size = 0;
+ size_t final_size = 0;
+ uint8_t *final = NULL;
+ uint32_t *ucs4 = NULL;
+ uint32_t *nrm = NULL;
+ uint8_t *nrmu8 = NULL;
+ unsigned i;
+ int ret;
+
+ if (plen == 0) {
+ out->data = (uint8_t*)gnutls_strdup("");
+ out->size = 0;
+ if (out->data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ return 0;
+ }
+
+ /* check for invalid UTF-8 */
+ if (u8_check((uint8_t*)password, plen) != NULL) {
+ gnutls_assert();
+ return GNUTLS_E_PARSING_ERROR;
+ }
+
+ /* convert to UTF-32 */
+ ucs4 = u8_to_u32((uint8_t*)password, plen, NULL, &ucs4_size);
+ if (ucs4 == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto fail;
+ }
+
+ /* convert all spaces to the ASCII-space */
+ for (i=0;i<ucs4_size;i++) {
+ if (uc_is_general_category(ucs4[i], UC_CATEGORY_Zs)) {
+ ucs4[i] = 0x20;
+ }
+ }
+
+ /* normalize to NFC */
+ nrm = u32_normalize(UNINORM_NFC, ucs4, ucs4_size, NULL, &nrm_size);
+ if (nrm == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto fail;
+ }
+
+ /* convert back to UTF-8 */
+ final_size = 0;
+ nrmu8 = u32_to_u8(nrm, nrm_size, NULL, &final_size);
+ if (nrmu8 == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto fail;
+ }
+
+ /* copy to output with null terminator */
+ final = gnutls_malloc(final_size+1);
+ if (final == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto fail;
+ }
+
+ memcpy(final, nrmu8, final_size);
+ final[final_size] = 0;
+
+ gnutls_free(ucs4);
+ gnutls_free(nrm);
+ gnutls_free(nrmu8);
+
+ out->data = final;
+ out->size = final_size;
+
+ return 0;
+
+ fail:
+ gnutls_free(final);
+ gnutls_free(ucs4);
+ gnutls_free(nrm);
+ gnutls_free(nrmu8);
+ return ret;
+}
+#else
+int gnutls_utf8_password_normalize(const uint8_t *password, unsigned password_len,
+ gnutls_datum_t *out, unsigned flags)
+{
+ if (!(flags & NORM_INTERNAL))
+ return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
+
+ out->data = gnutls_malloc(password_len+1);
+ if (out->data == NULL)
+ return GNUTLS_E_MEMORY_ERROR;
+ memcpy(out->data, password, password_len);
+ out->data[password_len] = 0;
+ out->size = password_len;
+ return 0;
+}
+#endif
diff --git a/lib/str.h b/lib/str.h
index 5bda483a64..fe9055b3eb 100644
--- a/lib/str.h
+++ b/lib/str.h
@@ -36,6 +36,10 @@
# define N_(String) String
#endif
+#define NORM_INTERNAL 1
+int gnutls_utf8_password_normalize(const uint8_t *password, unsigned password_len,
+ gnutls_datum_t *out, unsigned flags);
+
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);