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
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.
 
- 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]. 
-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
@@ -2822,6 +2824,9 @@ security of this protocol.
 [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
 
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;
-  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);
@@ -995,7 +995,18 @@ SILC_CLIENT_CMD_FUNC(join)
       }
       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,
-                                  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,
@@ -1016,6 +1026,7 @@ SILC_CLIENT_CMD_FUNC(join)
   silc_buffer_free(idp);
   if (auth)
     silc_buffer_free(auth);
+  silc_free(passphrase);
 
   /* Notify application */
   COMMAND;
@@ -1730,7 +1741,8 @@ SILC_CLIENT_CMD_FUNC(oper)
 }
 
 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;
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
- *    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,
@@ -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
-     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);
 
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;
+}