Fixed SILC_STRING_LDAP_DN encode/decode. Added
authorPekka Riikonen <priikone@silcnet.org>
Mon, 28 Mar 2005 21:45:59 +0000 (21:45 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 28 Mar 2005 21:45:59 +0000 (21:45 +0000)
SILC_STRING_UTF8_ESCAPE.

CHANGES
lib/silcclient/silcclient.h
lib/silcutil/silcstrutil.h
lib/silcutil/silcutf8.c
lib/silcutil/tests/test_silcstrutil.c

diff --git a/CHANGES b/CHANGES
index aba7caaf652019decb88a0b3baaa734b621aaffc..5ad094486b62658dc09c92b3fb6d1298d605299b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+Tue Mar 29 00:45:11 EEST 2005  Pekka Riikonen <priikone@silcnet.org>
+
+       * Fixed SILC_STRING_LDAP_DN encoding and decoding.  Affected
+         file lib/silcutil/silcutf8.c.
+
+       * Added SILC_STRING_UTF8_ESCAPE to lib/silcutil/silcstrutil.h.
+
 Mon Mar 28 22:46:23 CEST 2005  Jochen Eisinger <jochen@penguin-breeder.org>
 
        * Make public key in getkey reply mandatory.  Affected file
index edcf29061a852ecac8ac0c12b2abcc117d37c5df..8a02c2a6ea9e6a118163639b4bfae6ff40a2fa6f 100644 (file)
@@ -853,7 +853,7 @@ typedef struct {
   
   /* If this is set to TRUE, the silcclient library will not register and 
      deregister the cipher, pkcs, hash and hmac algorithms. The application
-        itself will need to handle that. */
+     itself will need to handle that. */
   bool dont_register_crypto_library;
 
 } SilcClientParams;
index 6525df50b0ff3f160a4de5ed952da1195babf67c..fe1243f96ade37d8bce7df0e5c7abe4a4682b04a 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 - 2004 Pekka Riikonen
+  Copyright (C) 2002 - 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
@@ -61,6 +61,7 @@ typedef enum {
   SILC_STRING_TELETEX       = 10, /* Teletex ASCII string */
   SILC_STRING_NUMERICAL     = 11, /* Numerical ASCII string (digits) */
   SILC_STRING_LDAP_DN       = 12, /* Strings for LDAP DNs, RFC 2253 */
+  SILC_STRING_UTF8_ESCAPE   = 12, /* Escaped UTF-8 as defined in RFC 2253 */
 
   SILC_STRING_LANGUAGE      = 6,  /* _Deprecated_, use SILC_STRING_LOCALE. */
 } SilcStringEncoding;
index 6c4168c1c43edd4c1802f4489d80cf640004387f..372d900b8fc3d34c368c7c80ea27551719eb8c03 100644 (file)
@@ -46,6 +46,49 @@ SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len,
     return bin_len;
   }
 
+  /* The SILC_STRING_LDAP_DN is alredy UTF-8 but it may be escaped.  We
+     remove the escaping and we're done. */
+  if (bin_encoding == SILC_STRING_LDAP_DN ||
+      bin_encoding == SILC_STRING_UTF8_ESCAPE) {
+    unsigned char cv;
+
+    for (i = 0; i < bin_len; i++) {
+      if (bin[i] == '\\') {
+       if (i + 1 >= bin_len)
+         return 0;
+
+       /* If escaped character is any of the following no processing is
+          needed, otherwise it is a hex value and we need to read it. */
+       cv = bin[i + 1];
+       if (cv != ',' && cv != '+' && cv != '"' && cv != '\\' && cv != '<' &&
+           cv != '>' && cv != ';' && cv != ' ' && cv != '#') {
+         unsigned int hexval;
+         if (i + 2 >= bin_len)
+           return 0;
+         if (sscanf(&bin[i + 1], "%02X", &hexval) != 1)
+           return 0;
+         if (utf8) {
+           if (enclen + 1 > utf8_size)
+             return 0;
+           utf8[enclen] = (unsigned char)hexval;
+         }
+
+         i += 2;
+         enclen++;
+       }
+      } else {
+       if (utf8) {
+         if (enclen + 1 > utf8_size)
+           return 0;
+         utf8[enclen] = bin[i];
+       }
+       enclen++;
+      }
+    }
+
+    return enclen;
+  }
+
   if (bin_encoding == SILC_STRING_LOCALE) {
 #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) && defined(CODESET)
     char *fromconv, *icp, *ocp;
@@ -121,31 +164,6 @@ SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len,
        return 0;
       charval = bin[i];
       break;
-    case SILC_STRING_LDAP_DN:
-      /* Remove any escaping */
-      if (bin[i] == '\\') {
-       unsigned char cv;
-       if (i + 1 >= bin_len)
-         return 0;
-
-       /* If escaped character is any of the following no processing is
-          needed, otherwise it is a hex value and we need to read it. */
-       cv = bin[++i];
-       if (cv != ',' && cv != '+' && cv != '"' && cv != '\\' && cv != '<' &&
-           cv != '>' && cv != ';' && cv != ' ' && cv != '#') {
-         unsigned int hexval;
-         if (i + 1 >= bin_len)
-           return 0;
-         if (sscanf(&bin[++i], "%02X", &hexval) != 1)
-           return 0;
-         cv = (unsigned char)hexval;
-       }
-
-       charval = cv;
-       break;
-      }
-      charval = bin[i];
-      break;
     default:
       return 0;
       break;
@@ -231,7 +249,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
                            SilcStringEncoding bin_encoding,
                            unsigned char *bin, SilcUInt32 bin_size)
 {
-  SilcUInt32 enclen = 0, i, charval;
+  SilcUInt32 enclen = 0, i, charval, bytes;
 
   if (!utf8 || !utf8_len)
     return 0;
@@ -277,6 +295,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
   for (i = 0; i < utf8_len; i++) {
     if ((utf8[i] & 0x80) == 0x00) {
       charval = utf8[i] & 0x7f;
+      bytes = 1;
     } else if ((utf8[i] & 0xe0) == 0xc0) {
       if (i + 1 >= utf8_len)
        return 0;
@@ -288,6 +307,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       charval |= utf8[i] & 0x3f;
       if (charval < 0x80)
         return 0;
+      bytes = 2;
     } else if ((utf8[i] & 0xf0) == 0xe0) {
       if (i + 2 >= utf8_len)
        return 0;
@@ -307,6 +327,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       charval |= utf8[i] & 0x3f;
       if (charval < 0x800)
         return 0;
+      bytes = 3;
     } else if ((utf8[i] & 0xf8) == 0xf0) {
       if (i + 3 >= utf8_len)
        return 0;
@@ -322,6 +343,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       charval |= utf8[i] & 0x3f;
       if (charval < 0x10000)
         return 0;
+      bytes = 4;
     } else if ((utf8[i] & 0xfc) == 0xf8) {
       if (i + 4 >= utf8_len)
        return 0;
@@ -339,6 +361,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       charval |= utf8[i] & 0x3f;
       if (charval < 0x200000)
         return 0;
+      bytes = 5;
     } else if ((utf8[i] & 0xfe) == 0xfc) {
       if (i + 5 >= utf8_len)
        return 0;
@@ -358,6 +381,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       charval |= utf8[i] & 0x3f;
       if (charval < 0x4000000)
         return 0;
+      bytes = 6;
     } else {
       return 0;
     }
@@ -414,64 +438,70 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       break;
     case SILC_STRING_LDAP_DN:
       {
-       /* XXX multibyte handling */
-       unsigned char cv = (unsigned char)charval;
+        int k;
+       unsigned char cv;
 
-       /* If string starts with space or # escape it */
-       if (!enclen && (cv == '#' || cv == ' ')) {
-         if (bin) {
-           if (enclen + 2 > bin_size)
-             return 0;
-           bin[enclen] = '\\';
-           bin[enclen + 1] = cv;
+       /* Non-printable UTF-8 characters will be escaped, printable will
+          be as is.  We take the bytes directly from the original data. */
+       for (k = 0; k < bytes; k++) {
+         cv = utf8[(i - (bytes - 1)) + k];
+
+         /* If string starts with space or # escape it */
+         if (!enclen && (cv == '#' || cv == ' ')) {
+           if (bin) {
+             if (enclen + 2 > bin_size)
+               return 0;
+             bin[enclen] = '\\';
+             bin[enclen + 1] = cv;
+           }
+           enclen += 2;
+           continue;
          }
-         enclen += 2;
-         break;
-       }
 
-       /* If string ends with space escape it */
-       if (i == utf8_len - 1 && cv == ' ') {
-         if (bin) {
-           if (enclen + 2 > bin_size)
-             return 0;
-           bin[enclen] = '\\';
-           bin[enclen + 1] = cv;
+         /* If string ends with space escape it */
+         if (i == utf8_len - 1 && cv == ' ') {
+           if (bin) {
+             if (enclen + 2 > bin_size)
+               return 0;
+             bin[enclen] = '\\';
+             bin[enclen + 1] = cv;
+           }
+           enclen += 2;
+           continue;
          }
-         enclen += 2;
-         break;
-       }
 
-       /* If character is any of following then escape */
-       if (cv == ',' || cv == '+' || cv == '"' || cv == '\\' || cv == '<' ||
-           cv == '>' || cv == ';') {
-         if (bin) {
-           if (enclen + 2 > bin_size)
-             return 0;
-           bin[enclen] = '\\';
-           bin[enclen + 1] = cv;
+         /* If character is any of following then escape */
+         if (cv == ',' || cv == '+' || cv == '"' || cv == '\\' || cv == '<' ||
+             cv == '>' || cv == ';') {
+           if (bin) {
+             if (enclen + 2 > bin_size)
+               return 0;
+             bin[enclen] = '\\';
+             bin[enclen + 1] = cv;
+           }
+           enclen += 2;
+           continue;
+         }
+
+         /* If character is not printable escape it with hex character */
+         if (!isprint((int)cv)) {
+           if (bin) {
+             if (enclen + 3 > bin_size)
+               return 0;
+             bin[enclen] = '\\';
+             snprintf(bin + enclen + 1, 3, "%02X", cv);
+           }
+           enclen += 3;
+           continue;
          }
-         enclen += 2;
-         break;
-       }
 
-       /* If character is not printable escape it with hex character */
-       if (!isprint((int)cv)) {
          if (bin) {
-           if (enclen + 2 > bin_size)
+           if (enclen + 1 > bin_size)
              return 0;
-           bin[enclen] = '\\';
-           snprintf(bin + enclen + 1, 3, "%02X", cv);
+           bin[enclen] = cv;
          }
-         enclen += 2;
-         break;
+         enclen++;
        }
-
-       if (bin) {
-         if (enclen + 1 > bin_size)
-           return 0;
-         bin[enclen] = cv;
-       }
-       enclen++;
       }
       break;
     default:
index 1e537a633c53fcb87b2a5df37f819fe36673e0fb..670cd3e1812b636bcb945b6895a770c294db7812 100644 (file)
@@ -51,6 +51,8 @@ utf8fail(30, "\xf0\x20\xf9\x20\xfa\x20\xfb\x20", 8);
 int main(int argc, char **argv)
 {
   bool success = FALSE;
+  unsigned char *s1, *s3, *s4;
+  int l;
 
   if (argc > 1 && !strcmp(argv[1], "-d")) {
     silc_debug = 1;
@@ -75,6 +77,34 @@ int main(int argc, char **argv)
   utf8failc(27);  utf8failc(28);
   utf8failc(29);  utf8failc(30);
 
+  /* LDAP DN simple test */
+  s1 = "#&?*Pekka, Riikonen, <foobar@foobar.com>\xc4\x8d ";
+  SILC_LOG_DEBUG(("s1 = %s", s1));
+
+  /* To LDAP DN */
+  l = silc_utf8_decoded_len(s1, strlen(s1), SILC_STRING_LDAP_DN);
+  if (!l)
+    goto err;
+  s3 = silc_calloc(l + 1, sizeof(*s3));
+  silc_utf8_decode(s1, strlen(s1), SILC_STRING_LDAP_DN, s3, l);
+  SILC_LOG_DEBUG(("ldapdn = %s", s3));
+
+  /* To UTF-8 */
+  l = silc_utf8_encoded_len(s3, strlen(s3), SILC_STRING_LDAP_DN);
+  if (!l)
+    goto err;  
+  s4 = silc_calloc(l + 1, sizeof(*s4));
+  silc_utf8_encode(s3, strlen(s3), SILC_STRING_LDAP_DN, s4, l);
+  SILC_LOG_DEBUG(("utf8 = %s", s4));
+
+  if (memcmp(s4, s1, strlen(s4))) {
+    SILC_LOG_DEBUG(("UTF-8 mismatch"));
+    goto err;
+  }
+
+  silc_free(s3);
+  silc_free(s4);
+
   success = TRUE;
 
  err: