Added casefolding stringprep profiles.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 30 Mar 2005 12:26:10 +0000 (12:26 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 30 Mar 2005 12:26:10 +0000 (12:26 +0000)
lib/silcutil/silcstringprep.c
lib/silcutil/silcstringprep.h
lib/silcutil/silcstrutil.c
lib/silcutil/silcstrutil.h
lib/silcutil/silcutil.c
lib/silcutil/silcutil.h
lib/silcutil/tests/test_silcstringprep.c

index ea4308d19e8104543df7870a6359edc2c1a3651a..736e219948b6427b0db1586fc83b01486cc3195d 100644 (file)
@@ -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;
 
index aa061b52fb634bf6e0017c142d1b2f96cb421779..b1759666d5df43611138d4782e096cf90aed11a7 100644 (file)
@@ -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
index e3b75fbffe1887f717418850d636a7635b3c15f3..8d36ef708953bbb042e086e5ee1f8d709b50c699 100644 (file)
@@ -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;
+}
index 98d0e7403f5a090d28d1e199a45a89a11bfa4224..e286ef1a76c11799f851128257d7f20e489fc0c1 100644 (file)
@@ -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 */
index c30024e8bcaef494bc05014a5cac87d7be78d418..8fbb564fa307d238e63c537b7f39f15079d84187 100644 (file)
@@ -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. */
 
index 5a0c9aec59af505da52904e1222dec9cb22cccdb..72aac63e4aad830e7325ed8a067b726e985bd05e 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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
index 81328e87804b946bc7e93be955b34374862c1e94..26ff2aaf9f5f9d6b5cec87d2b6c9b8c90808f743 100644 (file)
@@ -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: