updates.
authorPekka Riikonen <priikone@silcnet.org>
Fri, 5 Apr 2002 17:36:12 +0000 (17:36 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 5 Apr 2002 17:36:12 +0000 (17:36 +0000)
CHANGES
TODO
doc/draft-riikonen-silc-pp-05.nroff
lib/silcclient/command.c
lib/silcclient/silcclient.h
lib/silcutil/silcstrutil.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 299db091a746c76abf534389c6622aad3e0907eb..da17f33e55c353fbffe4771eaea58dfe2c8677c2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,23 @@
+Fri Apr  5 16:03:03 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Splitted lib/silcutil/silcutil.h into silcstrutil.h for
+         string utility functions.  Added there also new functions
+         silc_utf8_[encode/decode/valid] for UTF-8 string encoding.
+         Affected files lib/silcutil/silcstrutil.[ch].
+
+       * Renamed silc_*_pem functions to silc_pem_* functions.  Affected
+         files are lib/silcutil/silcstrutil.[ch].
+
+       * Defined that the security property fields in SKE SHOULD be
+         UTF-8 encoded, defined that version string MUST be US-ASCII
+         encoded, defined that passphrases sent in connection 
+         authentication protocol MUST be UTF-8 encoded.  Implemented
+         these to the client and server.  Defined also that other
+         passphrases sent in the protocol MUST be UTF-8 encoded.
+         Affected files are lib/silcske/silcske.c, 
+         lib/silcclient/protocol.c, silcd/protocol.c, 
+         silcd/serverconfig.c, and lib/silccore/silcauth.c.
+
 Wed Apr  3 16:24:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Upgraded the protocol version to 1.1, updated protocol specs
 Wed Apr  3 16:24:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Upgraded the protocol version to 1.1, updated protocol specs
diff --git a/TODO b/TODO
index 038bce1fb4e6508e7a80bf9e9f7a41c01cfd74b0..2f49dc644c2b308f7a8bbba1c9a30fe944d5083e 100644 (file)
--- a/TODO
+++ b/TODO
@@ -157,5 +157,16 @@ describe new stuff to be added to protocol versions 1.x.
  17. Cell wide channel founder support, and permanent channels when
      founder mode set.
 
  17. Cell wide channel founder support, and permanent channels when
      founder mode set.
 
- 18. UTF-8 requirement checkings for all specifications, when strings
-     are sent.  http://www.cl.cam.ac.uk/~mgk25/unicode.html
+ 18. Describe the SSH public key, X509, OpenPGP and SPKI certificates
+     encoding format in SKE (from their respective definitions).
+
+ o UTF-8 support/requirement for nicknames & channel names.  UTF-8 support
+   in terminals and OS's are so hazy that this matter is left for
+   consideration in next version of the protocol (1.2).  For good UTF-8
+   reference and tutorial see: http://www.cl.cam.ac.uk/~mgk25/unicode.html.
+   What should CLI application do if it receives nickname that it cannot
+   display without messing up the terminal?  If UTF-8 is mandatory in
+   SILC then SILC clients cannot be allowed to start on terminals that do
+   not support UTF-8 (which renders 98% of users unable to use CLI SILC
+   app without hacking their environment).  See also site
+   http://gratrix.net/unicode/
index 31b557d768cd9b1271cda40e125e821f5107e0cd..36dee34b6c08bc6de5424358f65d7b9ce270297f 100644 (file)
@@ -1189,7 +1189,9 @@ o Argument Nums (2 bytes) - Indicates the number of Argument
 
 The following list of currently defined notify types.  The format for
 notify arguments is same as in SILC commands described in [SILC4]. 
 
 The following list of currently defined notify types.  The format for
 notify arguments is same as in SILC commands described in [SILC4]. 
-Also, all ID's sent in arguments are sent inside ID Payload.
+Note that all ID's sent in arguments are sent inside ID Payload.  Also
+note that all passphrases that may be sent inside arguments MUST be
+UTF-8 [RFC2279] encoded.
 
 .in 6
 0     SILC_NOTIFY_TYPE_NONE
 
 .in 6
 0     SILC_NOTIFY_TYPE_NONE
@@ -2822,6 +2824,9 @@ security of this protocol.
 [SFTP]       Ylonen T., and Lehtinen S., "Secure Shell File Transfer
              Protocol", Internet Draft, March 2001.
 
 [SFTP]       Ylonen T., and Lehtinen S., "Secure Shell File Transfer
              Protocol", Internet Draft, March 2001.
 
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
 .ti 0
 5 Author's Address
 
 .ti 0
 5 Author's Address
 
index 7ffc279f4fa165c9b62e24332482fdfb1cd1a968..f6813f34b236c935a2fee66cb3acfeafa7dbd0a8 100644 (file)
@@ -948,8 +948,8 @@ SILC_CLIENT_CMD_FUNC(join)
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
   SilcBuffer buffer, idp, auth = NULL;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
   SilcBuffer buffer, idp, auth = NULL;
-  char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
-  int i;
+  char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
+  int i, passphrase_len = 0;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -995,7 +995,18 @@ SILC_CLIENT_CMD_FUNC(join)
       }
       i++;
     } else {
       }
       i++;
     } else {
-      passphrase = cmd->argv[i];
+      /* Passphrases must be UTF-8 encoded, so encode if it is not */
+      if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
+       passphrase_len = silc_utf8_encoded_len(cmd->argv[i], 
+                                              cmd->argv_lens[i], 0);
+       pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
+       passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
+                                         0, pu8, passphrase_len);
+       passphrase = pu8;
+      } else {
+       passphrase = strdup(cmd->argv[i]);
+       passphrase_len = cmd->argv_lens[i];
+      }
     }
   }
 
     }
   }
 
@@ -1004,8 +1015,7 @@ SILC_CLIENT_CMD_FUNC(join)
     silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
                                   1, name, strlen(name),
                                   2, idp->data, idp->len,
     silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
                                   1, name, strlen(name),
                                   2, idp->data, idp->len,
-                                  3, passphrase, 
-                                  passphrase ? strlen(passphrase) : 0,
+                                  3, passphrase, passphrase_len,
                                   4, cipher, cipher ? strlen(cipher) : 0,
                                   5, hmac, hmac ? strlen(hmac) : 0,
                                   6, auth ? auth->data : NULL,
                                   4, cipher, cipher ? strlen(cipher) : 0,
                                   5, hmac, hmac ? strlen(hmac) : 0,
                                   6, auth ? auth->data : NULL,
@@ -1016,6 +1026,7 @@ SILC_CLIENT_CMD_FUNC(join)
   silc_buffer_free(idp);
   if (auth)
     silc_buffer_free(auth);
   silc_buffer_free(idp);
   if (auth)
     silc_buffer_free(auth);
+  silc_free(passphrase);
 
   /* Notify application */
   COMMAND;
 
   /* Notify application */
   COMMAND;
@@ -1730,7 +1741,8 @@ SILC_CLIENT_CMD_FUNC(oper)
 }
 
 static void silc_client_command_silcoper_send(unsigned char *data,
 }
 
 static void silc_client_command_silcoper_send(unsigned char *data,
-                                             SilcUInt32 data_len, void *context)
+                                             SilcUInt32 data_len, 
+                                             void *context)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
index 5f9f44377f22e609d9cba26112e3a302a35bacbb..b9647bdf08bb705e159f6c947a9fc6a3ffb51e27 100644 (file)
@@ -183,7 +183,9 @@ typedef struct SilcChannelPrivateKeyStruct {
  *
  *    Ask passphrase callback. This is called by the application when the
  *    library calls `ask_passphrase' client operation.  The callback delivers
  *
  *    Ask passphrase callback. This is called by the application when the
  *    library calls `ask_passphrase' client operation.  The callback delivers
- *    the passphrase to the library.
+ *    the passphrase to the library.  The passphrases in SILC protocol
+ *    MUST be in UTF-8 encoding, therefore the `passphrase' SHOULD be UTF-8
+ *    encoded, and if it is not then library will attempt to encode it.
  *
  ***/
 typedef void (*SilcAskPassphrase)(unsigned char *passphrase,
  *
  ***/
 typedef void (*SilcAskPassphrase)(unsigned char *passphrase,
@@ -371,7 +373,8 @@ typedef struct {
 
   /* Ask (interact, that is) a passphrase from user. The passphrase is
      returned to the library by calling the `completion' callback with
 
   /* Ask (interact, that is) a passphrase from user. The passphrase is
      returned to the library by calling the `completion' callback with
-     the `context'. */
+     the `context'. The returned passphrase SHOULD be in UTF-8 encoded,
+     if not then the library will attempt to encode. */
   void (*ask_passphrase)(SilcClient client, SilcClientConnection conn,
                         SilcAskPassphrase completion, void *context);
 
   void (*ask_passphrase)(SilcClient client, SilcClientConnection conn,
                         SilcAskPassphrase completion, void *context);
 
diff --git a/lib/silcutil/silcstrutil.c b/lib/silcutil/silcstrutil.c
new file mode 100644 (file)
index 0000000..fa59894
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+
+  silcstrutil.c 
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2002 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+#include "silcstrutil.h"
+
+static unsigned char pem_enc[64] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
+   data string. Note: This is originally public domain code and is
+   still PD. */
+
+char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
+{
+  int i, j;
+  SilcUInt32 bits, c, char_count;
+  char *pem;
+
+  char_count = 0;
+  bits = 0;
+  j = 0;
+
+  pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
+
+  for (i = 0; i < len; i++) {
+    c = data[i];
+    bits += c;
+    char_count++;
+
+    if (char_count == 3) {
+      pem[j++] = pem_enc[bits  >> 18];
+      pem[j++] = pem_enc[(bits >> 12) & 0x3f];
+      pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
+      pem[j++] = pem_enc[bits & 0x3f];
+      bits = 0;
+      char_count = 0;
+    } else {
+      bits <<= 8;
+    }
+  }
+
+  if (char_count != 0) {
+    bits <<= 16 - (8 * char_count);
+    pem[j++] = pem_enc[bits >> 18];
+    pem[j++] = pem_enc[(bits >> 12) & 0x3f];
+
+    if (char_count == 1) {
+      pem[j++] = '=';
+      pem[j] = '=';
+    } else {
+      pem[j++] = pem_enc[(bits >> 6) & 0x3f];
+      pem[j] = '=';
+    }
+  }
+
+  return pem;
+}
+
+/* Same as above but puts newline ('\n') every 72 characters. */
+
+char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
+{
+  int i, j;
+  SilcUInt32 len, cols;
+  char *pem, *pem2;
+
+  pem = silc_pem_encode(data, data_len);
+  len = strlen(pem);
+
+  pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
+
+  for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
+    if (cols == 72) {
+      pem2[i] = '\n';
+      cols = 0;
+      len++;
+      continue;
+    }
+
+    pem2[i] = pem[j++];
+  }
+
+  silc_free(pem);
+  return pem2;
+}
+
+/* Decodes PEM into data. Returns the decoded data. Note: This is
+   originally public domain code and is still PD. */
+
+unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
+                              SilcUInt32 *ret_len)
+{
+  int i, j;
+  SilcUInt32 len, c, char_count, bits;
+  unsigned char *data;
+  static char ialpha[256], decoder[256];
+
+  for (i = 64 - 1; i >= 0; i--) {
+    ialpha[pem_enc[i]] = 1;
+    decoder[pem_enc[i]] = i;
+  }
+
+  char_count = 0;
+  bits = 0;
+  j = 0;
+
+  if (!pem_len)
+    len = strlen(pem);
+  else
+    len = pem_len;
+
+  data = silc_calloc(((len * 6) / 8), sizeof(*data));
+
+  for (i = 0; i < len; i++) {
+    c = pem[i];
+
+    if (c == '=')
+      break;
+
+    if (c > 127 || !ialpha[c])
+      continue;
+
+    bits += decoder[c];
+    char_count++;
+
+    if (char_count == 4) {
+      data[j++] = bits >> 16;
+      data[j++] = (bits >> 8) & 0xff;
+      data[j++] = bits & 0xff;
+      bits = 0;
+      char_count = 0;
+    } else {
+      bits <<= 6;
+    }
+  }
+
+  switch(char_count) {
+  case 1:
+    silc_free(data);
+    return NULL;
+    break;
+  case 2:
+    data[j++] = bits >> 10;
+    break;
+  case 3:
+    data[j++] = bits >> 16;
+    data[j++] = (bits >> 8) & 0xff;
+    break;
+  }
+
+  if (ret_len)
+    *ret_len = j;
+
+  return data;
+}
+
+/* Encodes the string `bin' of which encoding is `bin_encoding' to the
+   UTF-8 encoding into the buffer `utf8' which is of size of `utf8_size'.
+   Returns the length of the UTF-8 encoded string, or zero (0) on error.
+   By default `bin_encoding' is ASCII, and the caller needs to know the
+   encoding of the input string if it is anything else. */
+
+SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len,
+                           SilcStringEncoding bin_encoding,
+                           unsigned char *utf8, SilcUInt32 utf8_size)
+{
+  SilcUInt32 enclen = 0, i, charval = 0;
+
+  if (!bin || !bin_len)
+    return 0;
+
+  for (i = 0; i < bin_len; i++) {
+    switch (bin_encoding) {
+    case SILC_STRING_ASCII:
+      charval = bin[i];
+      break;
+    case SILC_STRING_ASCII_ESC:
+      break;
+    case SILC_STRING_BMP:
+      break;
+    case SILC_STRING_UNIVERSAL:
+      break;
+    }
+
+    if (charval < 0x80) {
+      if (utf8) {
+       if (enclen > utf8_size)
+         return 0;
+
+       utf8[enclen] = (unsigned char)charval;
+      }
+      enclen++;
+    } else if (charval < 0x800) {
+      if (utf8) {
+       if (enclen + 2 > utf8_size)
+         return 0;
+
+       utf8[enclen    ] = (unsigned char )(((charval >> 6)  & 0x1f) | 0xc0);
+       utf8[enclen + 1] = (unsigned char )((charval & 0x3f) | 0x80);
+      }
+      enclen += 2;
+    } else if (charval < 0x10000) {
+      if (utf8) {
+       if (enclen + 3 > utf8_size)
+         return 0;
+
+       utf8[enclen    ] = (unsigned char )(((charval >> 12) & 0xf)  | 0xe0);
+       utf8[enclen + 1] = (unsigned char )(((charval >> 6)  & 0x3f) | 0x80);
+       utf8[enclen + 2] = (unsigned char )((charval & 0x3f) | 0x80);
+      }
+      enclen += 3;
+    } else if (charval < 0x200000) {
+      if (utf8) {
+       if (enclen + 4 > utf8_size)
+         return 0;
+
+       utf8[enclen    ] = (unsigned char )(((charval >> 18) & 0x7)  | 0xf0);
+       utf8[enclen + 1] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80);
+       utf8[enclen + 2] = (unsigned char )(((charval >> 6)  & 0x3f) | 0x80);
+       utf8[enclen + 3] = (unsigned char )((charval & 0x3f) | 0x80);
+      }
+      enclen += 4;
+    } else if (charval < 0x4000000) {
+      if (utf8) {
+       if (enclen + 5 > utf8_size)
+         return 0;
+
+       utf8[enclen    ] = (unsigned char )(((charval >> 24) & 0x3)  | 0xf8);
+       utf8[enclen + 1] = (unsigned char )(((charval >> 18) & 0x3f) | 0x80);
+       utf8[enclen + 2] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80);
+       utf8[enclen + 3] = (unsigned char )(((charval >> 6)  & 0x3f) | 0x80);
+       utf8[enclen + 4] = (unsigned char )((charval & 0x3f) | 0x80);
+      }
+      enclen += 5;
+    } else {
+      if (utf8) {
+       if (enclen + 6 > utf8_size)
+         return 0;
+
+       utf8[enclen    ] = (unsigned char )(((charval >> 30) & 0x1)  | 0xfc);
+       utf8[enclen + 1] = (unsigned char )(((charval >> 24) & 0x3f) | 0x80);
+       utf8[enclen + 2] = (unsigned char )(((charval >> 18) & 0x3f) | 0x80);
+       utf8[enclen + 3] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80);
+       utf8[enclen + 4] = (unsigned char )(((charval >> 6)  & 0x3f) | 0x80);
+       utf8[enclen + 5] = (unsigned char )((charval & 0x3f) | 0x80);
+      }
+      enclen += 6;
+    }
+  }
+
+  return enclen;
+}
+
+/* Decodes UTF-8 encoded string `utf8' to string of which encoding is
+   to be `bin_encoding', into the `bin' buffer of size of `bin_size'.
+   Returns the length of the decoded buffer, or zero (0) on error.
+   By default `bin_encoding' is ASCII, and the caller needs to know to
+   which encoding the output string is to be encoded if ASCII is not
+   desired. */
+
+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;
+
+  if (!utf8 || !utf8_len)
+    return 0;
+
+  for (i = 0; i < utf8_len; i++) {
+    if ((utf8[i] & 0x80) == 0x00) {
+      charval = utf8[i] & 0x7f;
+    } else if ((utf8[i] & 0xe0) == 0xc0) {
+      if (utf8_len < 2)
+        return 0;
+
+      if ((utf8[i + 1] & 0xc0) != 0x80)
+        return 0;
+
+      charval = (utf8[i++] & 0x1f) << 6;
+      charval |= utf8[i] & 0x3f;
+      if (charval < 0x80)
+        return 0;
+    } else if ((utf8[i] & 0xf0) == 0xe0) {
+      if (utf8_len < 3)
+        return 0;
+
+      if (((utf8[i + 1] & 0xc0) != 0x80) || 
+         ((utf8[i + 2] & 0xc0) != 0x80))
+        return 0;
+
+      charval = (utf8[i++]  & 0xf)  << 12;
+      charval |= (utf8[i++] & 0x3f) << 6;
+      charval |= utf8[i] & 0x3f;
+      if (charval < 0x800)
+        return 0;
+    } else if ((utf8[i] & 0xf8) == 0xf0) {
+      if (utf8_len < 4)
+        return 0;
+
+      if (((utf8[i + 1] & 0xc0) != 0x80) || 
+         ((utf8[i + 2] & 0xc0) != 0x80) ||
+         ((utf8[i + 3] & 0xc0) != 0x80))
+        return 0;
+
+      charval = ((SilcUInt32)(utf8[i++] & 0x7)) << 18;
+      charval |= (utf8[i++] & 0x3f) << 12;
+      charval |= (utf8[i++] & 0x3f) << 6;
+      charval |= utf8[i] & 0x3f;
+      if (charval < 0x10000)
+        return 0;
+    } else if ((utf8[i] & 0xfc) == 0xf8) {
+      if (utf8_len < 5)
+        return 0;
+
+      if (((utf8[i + 1] & 0xc0) != 0x80) || 
+         ((utf8[i + 2] & 0xc0) != 0x80) ||
+         ((utf8[i + 3] & 0xc0) != 0x80) ||
+         ((utf8[i + 4] & 0xc0) != 0x80))
+        return 0;
+
+      charval = ((SilcUInt32)(utf8[i++]  & 0x3))  << 24;
+      charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 18;
+      charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 12;
+      charval |= (utf8[i++] & 0x3f) << 6;
+      charval |= utf8[i] & 0x3f;
+      if (charval < 0x200000)
+        return 0;
+    } else if ((utf8[i] & 0xfe) == 0xfc) {
+      if (utf8_len < 6)
+        return 0;
+
+      if (((utf8[i + 1] & 0xc0) != 0x80) || 
+         ((utf8[i + 2] & 0xc0) != 0x80) ||
+         ((utf8[i + 3] & 0xc0) != 0x80) ||
+         ((utf8[i + 4] & 0xc0) != 0x80) ||
+         ((utf8[i + 5] & 0xc0) != 0x80))
+        return 0;
+
+      charval = ((SilcUInt32)(utf8[i++]  & 0x1))  << 30;
+      charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 24;
+      charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 18;
+      charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 12;
+      charval |= (utf8[i++] & 0x3f) << 6;
+      charval |= utf8[i] & 0x3f;
+      if (charval < 0x4000000)
+        return 0;
+    } else {
+      return 0;
+    }
+
+    switch (bin_encoding) {
+    case SILC_STRING_ASCII:
+      if (bin) {
+        if (enclen + 1 > bin_size)
+          return 0;
+
+        bin[enclen] = (unsigned char)charval;
+      }
+      enclen++;
+      break;
+    case SILC_STRING_ASCII_ESC:
+      return 0;
+      break;
+    case SILC_STRING_BMP:
+      return 0;
+      break;
+    case SILC_STRING_UNIVERSAL:
+      return 0;
+      break;
+    }
+  }
+
+  return enclen;
+}
+
+/* Returns the length of UTF-8 encoded string if the `bin' of
+   encoding of `bin_encoding' is encoded with silc_utf8_encode. */
+
+SilcUInt32 silc_utf8_encoded_len(const unsigned char *bin, SilcUInt32 bin_len,
+                                SilcStringEncoding bin_encoding)
+{
+  return silc_utf8_encode(bin, bin_len, bin_encoding, NULL, 0);
+}
+
+/* Returns TRUE if the `utf8' string of length of `utf8_len' is valid
+   UTF-8 encoded string, FALSE if it is not UTF-8 encoded string. */
+
+bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len)
+{
+  return silc_utf8_decode(utf8, utf8_len, 0, NULL, 0) != 0;
+}