Esempio n. 1
0
static int
check (const uint32_t *input, size_t input_length,
       const uint32_t *expected, size_t expected_length)
{
  size_t length;
  uint32_t *result;

  /* Test return conventions with resultbuf == NULL.  */
  result = u32_normalize (UNINORM_NFKC, input, input_length, NULL, &length);
  if (!(result != NULL))
    return 1;
  if (!(length == expected_length))
    return 2;
  if (!(u32_cmp (result, expected, expected_length) == 0))
    return 3;
  free (result);

  /* Test return conventions with resultbuf too small.  */
  if (expected_length > 0)
    {
      uint32_t *preallocated;

      length = expected_length - 1;
      preallocated = (uint32_t *) malloc (length * sizeof (uint32_t));
      result = u32_normalize (UNINORM_NFKC, input, input_length, preallocated, &length);
      if (!(result != NULL))
        return 4;
      if (!(result != preallocated))
        return 5;
      if (!(length == expected_length))
        return 6;
      if (!(u32_cmp (result, expected, expected_length) == 0))
        return 7;
      free (result);
      free (preallocated);
    }

  /* Test return conventions with resultbuf large enough.  */
  {
    uint32_t *preallocated;

    length = expected_length;
    preallocated = (uint32_t *) malloc (length * sizeof (uint32_t));
    result = u32_normalize (UNINORM_NFKC, input, input_length, preallocated, &length);
    if (!(result != NULL))
      return 8;
    if (!(preallocated == NULL || result == preallocated))
      return 9;
    if (!(length == expected_length))
      return 10;
    if (!(u32_cmp (result, expected, expected_length) == 0))
      return 11;
    free (preallocated);
  }

  return 0;
}
Esempio n. 2
0
static int
check (const uint32_t *c1, size_t c1_length,
       const uint32_t *c2, size_t c2_length,
       const uint32_t *c3, size_t c3_length,
       const uint32_t *c4, size_t c4_length,
       const uint32_t *c5, size_t c5_length)
{
  /* Check
       c3 ==  NFD(c1) ==  NFD(c2) ==  NFD(c3)
       c5 ==  NFD(c4) ==  NFD(c5)
   */
  {
    size_t length;
    uint32_t *result;

    result = u32_normalize (UNINORM_NFD, c1, c1_length, NULL, &length);
    if (!(result != NULL
          && length == c3_length
          && u32_cmp (result, c3, c3_length) == 0))
      return 1;
    free (result);
  }
  {
    size_t length;
    uint32_t *result;

    result = u32_normalize (UNINORM_NFD, c2, c2_length, NULL, &length);
    if (!(result != NULL
          && length == c3_length
          && u32_cmp (result, c3, c3_length) == 0))
      return 2;
    free (result);
  }
  {
    size_t length;
    uint32_t *result;

    result = u32_normalize (UNINORM_NFD, c3, c3_length, NULL, &length);
    if (!(result != NULL
          && length == c3_length
          && u32_cmp (result, c3, c3_length) == 0))
      return 3;
    free (result);
  }
  {
    size_t length;
    uint32_t *result;

    result = u32_normalize (UNINORM_NFD, c4, c4_length, NULL, &length);
    if (!(result != NULL
          && length == c5_length
          && u32_cmp (result, c5, c5_length) == 0))
      return 4;
    free (result);
  }
  {
    size_t length;
    uint32_t *result;

    result = u32_normalize (UNINORM_NFD, c5, c5_length, NULL, &length);
    if (!(result != NULL
          && length == c5_length
          && u32_cmp (result, c5, c5_length) == 0))
      return 5;
    free (result);
  }
  return 0;
}
Esempio n. 3
0
/* Checks whether the provided string is in the valid set of FreeFormClass (RFC7564
 * as an RFC7613 requirement), and converts all spaces to the ASCII-space. */
static int check_for_valid_freeformclass(uint32_t *ucs4, unsigned ucs4_size)
{
	unsigned i;
	int rc;
	uint32_t tmp[4];
	size_t tmp_size;
	uint32_t *nrm;
	uc_general_category_t cat;
	unsigned is_invalid;

	/* make the union of Valid categories, excluding any invalid (i.e., control) */
	cat = uc_general_category_or(UC_CATEGORY_Ll, UC_CATEGORY_Lu); /* LetterDigits */
	cat = uc_general_category_or(cat, UC_CATEGORY_Lo);
	cat = uc_general_category_or(cat, UC_CATEGORY_Nd);
	cat = uc_general_category_or(cat, UC_CATEGORY_Lm);
	cat = uc_general_category_or(cat, UC_CATEGORY_Mn);
	cat = uc_general_category_or(cat, UC_CATEGORY_Mc);
	cat = uc_general_category_or(cat, UC_CATEGORY_Lt); /* OtherLetterDigits */
	cat = uc_general_category_or(cat, UC_CATEGORY_Nl);
	cat = uc_general_category_or(cat, UC_CATEGORY_No);
	cat = uc_general_category_or(cat, UC_CATEGORY_Me);
	cat = uc_general_category_or(cat, UC_CATEGORY_Sm); /* Symbols */
	cat = uc_general_category_or(cat, UC_CATEGORY_Sc);
	cat = uc_general_category_or(cat, UC_CATEGORY_So);
	cat = uc_general_category_or(cat, UC_CATEGORY_Sk);
	cat = uc_general_category_or(cat, UC_CATEGORY_Pc); /* Punctuation */
	cat = uc_general_category_or(cat, UC_CATEGORY_Pd);
	cat = uc_general_category_or(cat, UC_CATEGORY_Ps);
	cat = uc_general_category_or(cat, UC_CATEGORY_Pe);
	cat = uc_general_category_or(cat, UC_CATEGORY_Pi);
	cat = uc_general_category_or(cat, UC_CATEGORY_Pf);
	cat = uc_general_category_or(cat, UC_CATEGORY_Po);
	cat = uc_general_category_or(cat, UC_CATEGORY_Zs); /* Spaces */
	cat = uc_general_category_and_not(cat, UC_CATEGORY_Cc); /* Not in Control */

	/* check for being in the allowed sets in rfc7564#section-4.3 */
	for (i=0;i<ucs4_size;i++) {
		is_invalid = 0;

		/* Disallowed 
		   o  Old Hangul Jamo characters, i.e., the OldHangulJamo ("I") category
		      [FIXME: not handled in this code]

		   o  Control characters, i.e., the Controls ("L") category

		   o  Ignorable characters, i.e., the PrecisIgnorableProperties ("M")
		 */
		if (uc_is_property_default_ignorable_code_point(ucs4[i]) ||
		    uc_is_property_not_a_character(ucs4[i])) {
			return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_STRING);
		}


		/* Contextual rules - we do not implement them / we reject chars from these sets
		   o  A number of characters from the Exceptions ("F") category defined

		   o  Joining characters, i.e., the JoinControl ("H") category defined
		 */
		rc = is_allowed_exception(ucs4[i]);
		if (rc == 0 || uc_is_property_join_control(ucs4[i]))
			return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_STRING);

		if (rc == 1) /* exceptionally allowed, continue */
			continue;


		/* Replace all spaces; an RFC7613 requirement
		 */
		if (uc_is_general_category(ucs4[i], UC_CATEGORY_Zs)) /* replace */
			ucs4[i] = 0x20;

		/* Valid */
		if ((ucs4[i] < 0x21 || ucs4[i] > 0x7E) && !uc_is_general_category(ucs4[i], cat))
			is_invalid = 1;

		/* HasCompat */
		if (is_invalid) {
			tmp_size = sizeof(tmp)/sizeof(tmp[0]);
			nrm = u32_normalize(UNINORM_NFKC, &ucs4[i], 1, tmp, &tmp_size);
			if (nrm == NULL || (tmp_size == 1 && nrm[0] == ucs4[i]))
				return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_STRING);
		}
	}

	return 0;
}
Esempio n. 4
0
/**
 * gnutls_utf8_password_normalize:
 * @password: contain the UTF-8 formatted password
 * @plen: 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 the flag %GNUTLS_UTF8_IGNORE_ERRS is specified, any UTF-8 encoding
 * errors will be ignored, and in that case the output will be a copy of the input.
 *
 * Returns: %GNUTLS_E_INVALID_UTF8_STRING on invalid UTF-8 data, or 0 on success.
 *
 * Since: 3.5.7
 **/
int gnutls_utf8_password_normalize(const unsigned char *password, unsigned plen,
				   gnutls_datum_t *out, unsigned flags)
{
	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;
	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();
		if (flags & GNUTLS_UTF8_IGNORE_ERRS) {
 raw_copy:
			out->data = gnutls_malloc(plen+1);
			if (out->data == NULL)
				return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
			out->size = plen;
			memcpy(out->data, password, plen);
			out->data[plen] = 0;
			return 0;
		} else {
			return GNUTLS_E_INVALID_UTF8_STRING;
		}
	}

	/* 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;
	}

	ret = check_for_valid_freeformclass(ucs4, ucs4_size);
	if (ret < 0) {
		gnutls_assert();
		if (flags & GNUTLS_UTF8_IGNORE_ERRS) {
			free(ucs4);
			goto raw_copy;
		}
		if (ret == GNUTLS_E_INVALID_UTF8_STRING)
			ret = GNUTLS_E_INVALID_PASSWORD_STRING;
		goto fail;
	}

	/* normalize to NFC */
	nrm = u32_normalize(UNINORM_NFC, ucs4, ucs4_size, NULL, &nrm_size);
	if (nrm == NULL) {
		gnutls_assert();
		ret = GNUTLS_E_INVALID_PASSWORD_STRING;
		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_INVALID_PASSWORD_STRING;
		goto fail;
	}

	/* copy to output with null terminator */
	final = gnutls_malloc(final_size+1);