From 8714105433cec050183d1ddfe864d11767706ba1 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Wed, 30 Mar 2005 12:26:10 +0000 Subject: [PATCH] Added casefolding stringprep profiles. --- lib/silcutil/silcstringprep.c | 22 +++++++++ lib/silcutil/silcstringprep.h | 6 ++- lib/silcutil/silcstrutil.c | 27 +++++++++++ lib/silcutil/silcstrutil.h | 32 +++++++++++++ lib/silcutil/silcutil.c | 30 ++++++++++++ lib/silcutil/silcutil.h | 31 ++++++++++++- lib/silcutil/tests/test_silcstringprep.c | 59 ++++++++++++++++++++++++ 7 files changed, 205 insertions(+), 2 deletions(-) diff --git a/lib/silcutil/silcstringprep.c b/lib/silcutil/silcstringprep.c index ea4308d1..736e2199 100644 --- a/lib/silcutil/silcstringprep.c +++ b/lib/silcutil/silcstringprep.c @@ -91,6 +91,24 @@ const Stringprep_profile stringprep_silc_identifier_prep[] = {0} }; +/* Identifier string case folding and normalizing */ +const Stringprep_profile stringprep_silc_identifierc_prep[] = +{ + {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1}, + {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2}, + {STRINGPREP_NFKC, 0, 0}, + {0} +}; + +/* Case folding and normalizing */ +const Stringprep_profile stringprep_silc_casefold_prep[] = +{ + {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2}, + {STRINGPREP_NFKC, 0, 0}, + {0} +}; + + /* Prepares string according to the profile */ SilcStringprepStatus @@ -124,6 +142,10 @@ silc_stringprep(const unsigned char *bin, SilcUInt32 bin_len, /* Check profile. */ if (!strcmp(profile_name, SILC_IDENTIFIER_PREP)) profile = stringprep_silc_identifier_prep; + else if (!strcmp(profile_name, SILC_IDENTIFIERC_PREP)) + profile = stringprep_silc_identifierc_prep; + else if (!strcmp(profile_name, SILC_CASEFOLD_PREP)) + profile = stringprep_silc_casefold_prep; else return SILC_STRINGPREP_ERR_UNSUP_PROFILE; diff --git a/lib/silcutil/silcstringprep.h b/lib/silcutil/silcstringprep.h index aa061b52..b1759666 100644 --- a/lib/silcutil/silcstringprep.h +++ b/lib/silcutil/silcstringprep.h @@ -81,6 +81,8 @@ typedef enum { /* Profiles */ #define SILC_IDENTIFIER_PREP "silc-identifier-prep" +#define SILC_IDENTIFIERC_PREP "silc-identifierc-prep" +#define SILC_CASEFOLD_PREP "silc-casefold-prep" /****f* silcutil/SilcStringprep/silc_stringprep * @@ -118,7 +120,9 @@ typedef enum { * * Available profile names: * - * SILC_IDENTIFIER_PREP + * SILC_IDENTIFIER_PREP Prepares SILC identifier strings + * SILC_IDENTIFIERC_PREP Casefolds identifier strings + * SILC_CASEFOLD_PREP Casefolding and normalizing * ***/ SilcStringprepStatus diff --git a/lib/silcutil/silcstrutil.c b/lib/silcutil/silcstrutil.c index e3b75fbf..8d36ef70 100644 --- a/lib/silcutil/silcstrutil.c +++ b/lib/silcutil/silcstrutil.c @@ -309,3 +309,30 @@ unsigned char *silc_identifier_check(const unsigned char *identifier, return utf8s; } + +/* Same as above but does not allocate memory, just checks the + validity of the string. */ + +bool silc_identifier_verify(const unsigned char *identifier, + SilcUInt32 identifier_len, + SilcStringEncoding identifier_encoding, + SilcUInt32 max_allowed_length) +{ + SilcStringprepStatus status; + + if (!identifier || !identifier_len) + return FALSE; + + if (max_allowed_length && identifier_len > max_allowed_length) + return FALSE; + + status = silc_stringprep(identifier, identifier_len, + identifier_encoding, SILC_IDENTIFIER_PREP, 0, + NULL, NULL, SILC_STRING_UTF8); + if (status != SILC_STRINGPREP_OK) { + SILC_LOG_DEBUG(("silc_stringprep() status error %d", status)); + return FALSE; + } + + return TRUE; +} diff --git a/lib/silcutil/silcstrutil.h b/lib/silcutil/silcstrutil.h index 98d0e740..e286ef1a 100644 --- a/lib/silcutil/silcstrutil.h +++ b/lib/silcutil/silcstrutil.h @@ -213,4 +213,36 @@ unsigned char *silc_identifier_check(const unsigned char *identifier, SilcUInt32 max_allowed_length, SilcUInt32 *out_len); +/****f* silcutil/SilcStrUtilAPI/silc_identifier_verify + * + * SYNOPSIS + * + * bool + * silc_identifier_check(const unsigned char *identifier, + * SilcUInt32 identifier_len, + * SilcStringEncoding identifier_encoding, + * SilcUInt32 max_allowed_length); + * + * DESCRIPTION + * + * Checks that the 'identifier' string is valid identifier string + * and does not contain any unassigned or prohibited character. This + * function is used to check for valid nicknames, channel names, + * server names, usernames, hostnames, service names, algorithm names, + * other security property names, and SILC Public Key name. + * + * If the 'max_allowed_length' is non-zero the identifier cannot be + * longer than that, and NULL is returned if it is. If zero (0), no + * length limit exist. For nicknames the max length must be 128 bytes + * and for channel names 256 bytes. Other identifiers has no default + * limit, but application may choose one anyway. + * + * Returns TRUE if the string is valid and FALSE if it is prohibited. + * + ***/ +bool silc_identifier_verify(const unsigned char *identifier, + SilcUInt32 identifier_len, + SilcStringEncoding identifier_encoding, + SilcUInt32 max_allowed_length); + #endif /* SILCSTRUTIL_H */ diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index c30024e8..8fbb564f 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -467,6 +467,25 @@ SilcUInt32 silc_hash_string(void *key, void *user_context) return h; } +/* Hash UTF-8 string */ + +SilcUInt32 silc_hash_utf8_string(void *key, void *user_context) +{ + unsigned char *s = (unsigned char *)key; + SilcUInt32 h = 0, g; + + while (*s != '\0') { + h = (h << 4) + *s; + if ((g = h & 0xf0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + s++; + } + + return h; +} + /* Basic hash function to hash integers. May be used with the SilcHashTable. */ SilcUInt32 silc_hash_uint(void *key, void *user_context) @@ -609,6 +628,17 @@ bool silc_hash_data_compare(void *key1, void *key2, void *user_context) return !memcmp(key1, key2, len); } +/* Compares UTF-8 string. */ + +bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context) +{ + int l1 = strlen((char *)key1); + int l2 = strlen((char *)key2); + if (l1 > l2) + l2 = l1; + return !memcmp(key1, key2, l2); +} + /* Compares two SILC Public keys. It may be used as SilcHashTable comparison function. */ diff --git a/lib/silcutil/silcutil.h b/lib/silcutil/silcutil.h index 5a0c9aec..72aac63e 100644 --- a/lib/silcutil/silcutil.h +++ b/lib/silcutil/silcutil.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2003 Pekka Riikonen + Copyright (C) 1997 - 2005 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -196,6 +196,21 @@ int silc_string_compare(char *string1, char *string2); ***/ SilcUInt32 silc_hash_string(void *key, void *user_context); +/****f* silcutil/SilcUtilAPI/silc_hash_utf8_string + * + * SYNOPSIS + * + * SilcUInt32 silc_hash_utf8_string(void *key, void *user_context); + * + * DESCRIPTION + * + * Basic has function to hash UTF-8 strings. May be used with the + * SilcHashTable. Used with identifier strings. The key is + * expected to be casefolded. + * + ***/ +SilcUInt32 silc_hash_utf8_string(void *key, void *user_context); + /****f* silcutil/SilcUtilAPI/silc_hash_uint * * SYNOPSIS @@ -330,6 +345,20 @@ bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context); ***/ bool silc_hash_data_compare(void *key1, void *key2, void *user_context); +/****f* silcutil/SilcUtilAPI/silc_hash_utf8_compare + * + * SYNOPSIS + * + * bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context); + * + * DESCRIPTION + * + * Compares UTF-8 strings. Casefolded and NULL terminated strings are + * expected. May be used as SilcHashTable comparison function. + * + ***/ +bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context); + /****f* silcutil/SilcUtilAPI/silc_hash_public_key_compare * * SYNOPSIS diff --git a/lib/silcutil/tests/test_silcstringprep.c b/lib/silcutil/tests/test_silcstringprep.c index 81328e87..26ff2aaf 100644 --- a/lib/silcutil/tests/test_silcstringprep.c +++ b/lib/silcutil/tests/test_silcstringprep.c @@ -48,6 +48,26 @@ const test_st tests[] = { SILC_STRINGPREP_ERR_PROHIBITED}, }; +const test_st tests_norm[] = { + {"Casefold 1", + "Pekka Riikonen", "pekka riikonen"}, + {"Casefold 2", + "PEKKA RIIKONEN", "pekka riikonen"}, + {"Casefold 3", + "pekka riikonen", "pekka riikonen"}, + {"Casefold 4", + "#ksPPPAA", "#kspppaa"}, + {"Normal casefold", + "Foobbeli-BofJFlkJDF", "foobbeli-bofjflkjdf"}, + {"Nothing", + "sauna.silcnet.org", "sauna.silcnet.org"}, + {"Locale test", + "Päivää", "päivää", 0, SILC_STRING_LOCALE}, + {"Locale test2", + "#öäöö/&#\\#(&(&#(.äöäÄÖäÄÖÄÖ^'", + "#öäöö/&#\\#(&(&#(.äöääöääöäö^'", 0, SILC_STRING_LOCALE}, +}; + int main(int argc, char **argv) { bool success = FALSE; @@ -62,6 +82,8 @@ int main(int argc, char **argv) silc_log_set_debug_string("*stringprep*,*utf8*"); } + SILC_LOG_DEBUG(("--- Identifier string tests")); + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { SILC_LOG_DEBUG(("Test case %d", i)); SILC_LOG_DEBUG((" %d: %s", i, tests[i].comment)); @@ -97,6 +119,43 @@ int main(int argc, char **argv) out = NULL; } + SILC_LOG_DEBUG(("--- Casefold tests")); + + for (i = 0; i < sizeof(tests_norm) / sizeof(tests_norm[0]); i++) { + SILC_LOG_DEBUG(("Test case %d", i)); + SILC_LOG_DEBUG((" %d: %s", i, tests_norm[i].comment)); + SILC_LOG_DEBUG((" %d: in: %s", i, tests_norm[i].in)); + SILC_LOG_DEBUG((" %d: out: %s", i, tests_norm[i].out)); + SILC_LOG_DEBUG((" %d: ret: %d", i, tests_norm[i].ret)); + + if (!tests_norm[i].enc) + enc = SILC_STRING_UTF8; + else + enc = tests_norm[i].enc; + ret = silc_stringprep(tests_norm[i].in, strlen(tests_norm[i].in), + enc, SILC_CASEFOLD_PREP, 0, + &out, &out_len, enc); + if (ret != SILC_STRINGPREP_OK) { + if (tests_norm[i].ret != SILC_STRINGPREP_OK) { + SILC_LOG_DEBUG((" %d: Expected ret %d", i, ret)); + } else { + SILC_LOG_DEBUG(("%d: Error: %d", i, ret)); + goto err; + } + } else { + SILC_LOG_DEBUG((" %d: prepared out: %s", i, out)); + SILC_LOG_HEXDUMP((" %d: prepared dump", i), out, out_len); + if (memcmp(out, tests_norm[i].out, out_len)) { + SILC_LOG_DEBUG((" %d: Output mismatch", i)); + goto err; + } + } + SILC_LOG_DEBUG((" %d: Output match", i)); + + silc_free(out); + out = NULL; + } + success = TRUE; err: -- 2.24.0