diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-11-08 13:00:16 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2016-11-20 12:13:26 +0100 |
commit | d753cfdcfc7e5342a38f27dde41cf8eb530b57a3 (patch) | |
tree | bccdff920f6b2682db3c279deac939f24d60330a | |
parent | e7785d07443a85ed85347c5413acd5194e026c9e (diff) | |
download | gnutls-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.ac | 5 | ||||
-rw-r--r-- | lib/Makefile.am | 6 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 3 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 | ||||
-rw-r--r-- | lib/str-unicode.c | 146 | ||||
-rw-r--r-- | lib/str.h | 4 |
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 @@ -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); |