LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib - str-unicode.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 107 124 86.3 %
Date: 2020-10-30 04:50:48 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2016, 2017 Red Hat, Inc.
       3             :  *
       4             :  * Author: Nikos Mavrogiannopoulos
       5             :  *
       6             :  * This file is part of GnuTLS.
       7             :  *
       8             :  * The GnuTLS is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public License
      10             :  * as published by the Free Software Foundation; either version 2.1 of
      11             :  * the License, or (at your option) any later version.
      12             :  *
      13             :  * This library is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public License
      19             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      20             :  *
      21             :  */
      22             : 
      23             : #include "gnutls_int.h"
      24             : #include "errors.h"
      25             : #include "str.h"
      26             : #include <uninorm.h>
      27             : #include <unistr.h>
      28             : #include <unictype.h>
      29             : 
      30             : /* rfc5892#section-2.6 exceptions
      31             :  */
      32        4743 : inline static int is_allowed_exception(uint32_t ch)
      33             : {
      34        4743 :         switch (ch) {
      35             :                 case 0xB7:
      36             :                 case 0x0375:
      37             :                 case 0x05F3:
      38             :                 case 0x05F4:
      39             :                 case 0x30FB:
      40             :                 case 0x0660:
      41             :                 case 0x0661:
      42             :                 case 0x0662:
      43             :                 case 0x0663:
      44             :                 case 0x0664:
      45             :                 case 0x0665:
      46             :                 case 0x0666:
      47             :                 case 0x0667:
      48             :                 case 0x0668:
      49             :                 case 0x0669:
      50             :                 case 0x06F0:
      51             :                 case 0x06F1:
      52             :                 case 0x06F2:
      53             :                 case 0x06F3:
      54             :                 case 0x06F4:
      55             :                 case 0x06F5:
      56             :                 case 0x06F6:
      57             :                 case 0x06F7:
      58             :                 case 0x06F8:
      59             :                 case 0x06F9:
      60             :                 case 0x0640:
      61             :                 case 0x07FA:
      62             :                 case 0x302E:
      63             :                 case 0x302F:
      64             :                 case 0x3031:
      65             :                 case 0x3032:
      66             :                 case 0x3033:
      67             :                 case 0x3034:
      68             :                 case 0x3035:
      69             :                 case 0x303B:
      70             :                         return 0; /* disallowed */
      71           2 :                 case 0xDF:
      72             :                 case 0x03C2:
      73             :                 case 0x06FD:
      74             :                 case 0x06FE:
      75             :                 case 0x0F0B:
      76             :                 case 0x3007:
      77           2 :                         return 1; /* allowed */
      78        4735 :                 default:
      79        4735 :                         return -1; /* not exception */
      80             :         }
      81             : }
      82             : 
      83             : /* Checks whether the provided string is in the valid set of FreeFormClass (RFC7564
      84             :  * as an RFC7613 requirement), and converts all spaces to the ASCII-space. */
      85         946 : static int check_for_valid_freeformclass(uint32_t *ucs4, unsigned ucs4_size)
      86             : {
      87         946 :         unsigned i;
      88         946 :         int rc;
      89         946 :         uint32_t tmp[4];
      90         946 :         size_t tmp_size;
      91         946 :         uint32_t *nrm;
      92         946 :         uc_general_category_t cat;
      93         946 :         unsigned is_invalid;
      94             : 
      95             :         /* make the union of Valid categories, excluding any invalid (i.e., control) */
      96         946 :         cat = uc_general_category_or(UC_CATEGORY_Ll, UC_CATEGORY_Lu); /* LetterDigits */
      97         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Lo);
      98         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Nd);
      99         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Lm);
     100         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Mn);
     101         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Mc);
     102         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Lt); /* OtherLetterDigits */
     103         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Nl);
     104         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_No);
     105         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Me);
     106         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Sm); /* Symbols */
     107         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Sc);
     108         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_So);
     109         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Sk);
     110         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Pc); /* Punctuation */
     111         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Pd);
     112         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Ps);
     113         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Pe);
     114         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Pi);
     115         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Pf);
     116         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Po);
     117         946 :         cat = uc_general_category_or(cat, UC_CATEGORY_Zs); /* Spaces */
     118         946 :         cat = uc_general_category_and_not(cat, UC_CATEGORY_Cc); /* Not in Control */
     119             : 
     120             :         /* check for being in the allowed sets in rfc7564#section-4.3 */
     121        6627 :         for (i=0;i<ucs4_size;i++) {
     122        4748 :                 is_invalid = 0;
     123             : 
     124             :                 /* Disallowed 
     125             :                    o  Old Hangul Jamo characters, i.e., the OldHangulJamo ("I") category
     126             :                       (not handled in this code)
     127             : 
     128             :                    o  Control characters, i.e., the Controls ("L") category
     129             : 
     130             :                    o  Ignorable characters, i.e., the PrecisIgnorableProperties ("M")
     131             :                  */
     132        4748 :                 if (uc_is_property_default_ignorable_code_point(ucs4[i]) ||
     133        4744 :                     uc_is_property_not_a_character(ucs4[i])) {
     134           5 :                         return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_STRING);
     135             :                 }
     136             : 
     137             : 
     138             :                 /* Contextual rules - we do not implement them / we reject chars from these sets
     139             :                    o  A number of characters from the Exceptions ("F") category defined
     140             : 
     141             :                    o  Joining characters, i.e., the JoinControl ("H") category defined
     142             :                  */
     143        4743 :                 rc = is_allowed_exception(ucs4[i]);
     144        4743 :                 if (rc == 0 || uc_is_property_join_control(ucs4[i]))
     145           6 :                         return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_STRING);
     146             : 
     147        4737 :                 if (rc == 1) /* exceptionally allowed, continue */
     148           2 :                         continue;
     149             : 
     150             : 
     151             :                 /* Replace all spaces; an RFC7613 requirement
     152             :                  */
     153        4735 :                 if (uc_is_general_category(ucs4[i], UC_CATEGORY_Zs)) /* replace */
     154         122 :                         ucs4[i] = 0x20;
     155             : 
     156             :                 /* Valid */
     157        4735 :                 if ((ucs4[i] < 0x21 || ucs4[i] > 0x7E) && !uc_is_general_category(ucs4[i], cat))
     158           2 :                         is_invalid = 1;
     159             : 
     160             :                 /* HasCompat */
     161           2 :                 if (is_invalid) {
     162           2 :                         tmp_size = sizeof(tmp)/sizeof(tmp[0]);
     163           2 :                         nrm = u32_normalize(UNINORM_NFKC, &ucs4[i], 1, tmp, &tmp_size);
     164           2 :                         if (nrm == NULL || (tmp_size == 1 && nrm[0] == ucs4[i]))
     165           2 :                                 return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_STRING);
     166             :                 }
     167             :         }
     168             : 
     169             :         return 0;
     170             : }
     171             : 
     172             : 
     173             : /**
     174             :  * gnutls_utf8_password_normalize:
     175             :  * @password: contain the UTF-8 formatted password
     176             :  * @plen: the length of the provided password
     177             :  * @out: the result in an null-terminated allocated string
     178             :  * @flags: should be zero
     179             :  *
     180             :  * This function will convert the provided UTF-8 password according
     181             :  * to the normalization rules in RFC7613.
     182             :  *
     183             :  * If the flag %GNUTLS_UTF8_IGNORE_ERRS is specified, any UTF-8 encoding
     184             :  * errors will be ignored, and in that case the output will be a copy of the input.
     185             :  *
     186             :  * Returns: %GNUTLS_E_INVALID_UTF8_STRING on invalid UTF-8 data, or 0 on success.
     187             :  *
     188             :  * Since: 3.5.7
     189             :  **/
     190         953 : int gnutls_utf8_password_normalize(const unsigned char *password, unsigned plen,
     191             :                                    gnutls_datum_t *out, unsigned flags)
     192             : {
     193         953 :         size_t ucs4_size = 0, nrm_size = 0;
     194         953 :         size_t final_size = 0;
     195         953 :         uint8_t *final = NULL;
     196         953 :         uint32_t *ucs4 = NULL;
     197         953 :         uint32_t *nrm = NULL;
     198         953 :         uint8_t *nrmu8 = NULL;
     199         953 :         int ret;
     200             : 
     201         953 :         if (plen == 0) {
     202           7 :                 out->data = (uint8_t*)gnutls_strdup("");
     203           7 :                 out->size = 0;
     204           7 :                 if (out->data == NULL)
     205           0 :                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     206             :                 return 0;
     207             :         }
     208             : 
     209             :         /* check for invalid UTF-8 */
     210         946 :         if (u8_check((uint8_t*)password, plen) != NULL) {
     211           0 :                 gnutls_assert();
     212           0 :                 if (flags & GNUTLS_UTF8_IGNORE_ERRS) {
     213           0 :  raw_copy:
     214           5 :                         out->data = gnutls_malloc(plen+1);
     215           5 :                         if (out->data == NULL)
     216           0 :                                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     217           5 :                         out->size = plen;
     218           5 :                         memcpy(out->data, password, plen);
     219           5 :                         out->data[plen] = 0;
     220           5 :                         return 0;
     221             :                 } else {
     222             :                         return GNUTLS_E_INVALID_UTF8_STRING;
     223             :                 }
     224             :         }
     225             : 
     226             :         /* convert to UTF-32 */
     227         946 :         ucs4 = u8_to_u32((uint8_t*)password, plen, NULL, &ucs4_size);
     228         946 :         if (ucs4 == NULL) {
     229           0 :                 gnutls_assert();
     230           0 :                 ret = GNUTLS_E_PARSING_ERROR;
     231           0 :                 goto fail;
     232             :         }
     233             : 
     234         946 :         ret = check_for_valid_freeformclass(ucs4, ucs4_size);
     235         946 :         if (ret < 0) {
     236          13 :                 gnutls_assert();
     237          13 :                 if (flags & GNUTLS_UTF8_IGNORE_ERRS) {
     238           5 :                         free(ucs4);
     239           5 :                         goto raw_copy;
     240             :                 }
     241           8 :                 if (ret == GNUTLS_E_INVALID_UTF8_STRING)
     242           8 :                         ret = GNUTLS_E_INVALID_PASSWORD_STRING;
     243           8 :                 goto fail;
     244             :         }
     245             : 
     246             :         /* normalize to NFC */
     247         933 :         nrm = u32_normalize(UNINORM_NFC, ucs4, ucs4_size, NULL, &nrm_size);
     248         933 :         if (nrm == NULL) {
     249           0 :                 gnutls_assert();
     250           0 :                 ret = GNUTLS_E_INVALID_PASSWORD_STRING;
     251           0 :                 goto fail;
     252             :         }
     253             : 
     254             :         /* convert back to UTF-8 */
     255         933 :         final_size = 0;
     256         933 :         nrmu8 = u32_to_u8(nrm, nrm_size, NULL, &final_size);
     257         933 :         if (nrmu8 == NULL) {
     258           0 :                 gnutls_assert();
     259           0 :                 ret = GNUTLS_E_INVALID_PASSWORD_STRING;
     260           0 :                 goto fail;
     261             :         }
     262             : 
     263             :         /* copy to output with null terminator */
     264         933 :         final = gnutls_malloc(final_size+1);
     265         933 :         if (final == NULL) {
     266           0 :                 gnutls_assert();
     267           0 :                 ret = GNUTLS_E_MEMORY_ERROR;
     268           0 :                 goto fail;
     269             :         }
     270             : 
     271         933 :         memcpy(final, nrmu8, final_size);
     272         933 :         final[final_size] = 0;
     273             : 
     274         933 :         free(ucs4);
     275         933 :         free(nrm);
     276         933 :         free(nrmu8);
     277             : 
     278         933 :         out->data = final;
     279         933 :         out->size = final_size;
     280             : 
     281         933 :         return 0;
     282             : 
     283           8 :  fail:
     284           8 :         gnutls_free(final);
     285           8 :         free(ucs4);
     286           8 :         free(nrm);
     287           8 :         free(nrmu8);
     288           8 :         return ret;
     289             : }
     290             : 

Generated by: LCOV version 1.14