updates.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 1 Apr 2001 20:07:47 +0000 (20:07 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 1 Apr 2001 20:07:47 +0000 (20:07 +0000)
28 files changed:
CHANGES
README
TODO
apps/silc/client_ops.c
apps/silc/local_command.c
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/protocol.c
apps/silcd/server.c
doc/draft-riikonen-silc-ke-auth-02.nroff
doc/draft-riikonen-silc-spec-01.nroff
doc/draft-riikonen-silc-spec-02.nroff
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/command.c
lib/silcclient/protocol.c
lib/silcclient/silcapi.h
lib/silccore/silcauth.c
lib/silccore/silcauth.h
lib/silccore/silcmode.h
lib/silccrypt/silcpkcs.c
lib/silcske/payload.c
lib/silcske/payload.h
lib/silcske/payload_internal.h
lib/silcske/silcske.c
lib/silcske/silcske.h

diff --git a/CHANGES b/CHANGES
index 81ef7f01b9d9478a1a3a259821c8a9cc3ca71ab6..235599ae27b0b47a8f6f950820d2722983b34424 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,83 @@
+Sun Apr  1 19:49:34 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added SILC_UMODE_GONE mode to indicate when the client is not
+         present in the SILC network.  Added also support to the local
+         command AWAY that will set this mode.  Added support of showing
+         "xxx is gone" in WHOIS command.  The USERS command shows the
+         gone status as well.
+
+       * Fixed setting server and router operator privileges in the
+         server's UMODE command.  Affected file silcd/command.c.
+
+       * Merged the SKE KE1 and KE2 payloads into one payload.  The
+         new KE payload is equivalent to the old KE2 payload.
+
+         Cleaned up the SKE Start Payload parsing.  It now uses the
+         simple buffer unformatting to do the parsing.  A lot faster
+         now.
+
+         Added new Mutual Authentication flag (SILC_SKE_SP_FLAG_MUTUAL)
+         to the SKE that is used to indicate whether both of the SKE
+         parties should perform authentication.  By default only the
+         responder performs authentication.  By setting this flag also
+         the initiator must do authentication.  By default it is unset
+         since in normal SKE case, client to server connection, only
+         the responder should do authentication.  When doing SKE between
+         two clients both should perform authentication.  Updated the
+         code and the protocol specs.
+
+       * A little fix to IDENTIFY command in the server.  Search the
+         client first by hash not nickname.  Affected file is 
+         silcd/command.c.
+
+       * Fixed the silc_client_close_connection to support closing
+         the client to client connections wihtout deleting too much
+         data.  Affected file lib/silcclient/client.c.
+
+       * Fixed a fatal bug in server and client; if KE1 or KE2 packets
+         are received if protocol used to be active but is not anymore
+         the application would crash due to NULL pointer dereference.
+         Affected files silcd/server.c and lib/silcclient/client.c.
+
+       * Added `hash' field to the SilcClientConnection to include
+         the hash function negotiated in the SKE protocol.
+
+       * Added new channel mode SILC_CMODE_FOUNDER_AUTH that is used
+         to set the channel founder authentication data.  A client can
+         claim the founder rights later by providing the authentication
+         data to the CUMODE command using SILC_CUMODE_FOUNDER mode.
+         This way the channel founder can regain the channel founder
+         privileges even it is left the channel.  This works only on
+         local server and the client must be connected to the same
+         server to be able to regain the founder rights.  Updated the
+         protocol specs accordingly.
+
+         Added support to the CMODE command in the client to set the
+         founder auth data.  Read the README to see how to set it.
+
+         Added support to the CUMODE command to claim the founder
+         rights.  Read the README to see how to do it.
+
+         Added support for the founder authentication to the Channel
+         Entry in the server.  Affected file silcd/idlist.h.
+
+         Added support for the SILC_CMODE_FOUNDER_AUTH mode in the
+         server's CMODE command.  Affected file silcd/command.c.
+
+       * Added the following new functions into lib/silccore/silcauth.[ch]:
+         silc_auth_get_method and silc_auth_get_data.    
+
+       * The server now saves the remote hosts public key to the
+         SilcIDListData pointer.  Affected file silcd/protocol.c.
+
+       * The normal server now does not remove the channel entry from
+         the cache if the founder authentication data is set.  It used
+         to remove it if the founder was the last one on the channel on 
+         the server and left the channel.  The auth data is saved and
+         if the channel is re-joined later the old entry is used with
+         the old auth data.  Affected files silcd/command_reply.c and
+         silcd/server.c.
+
 Sat Mar 31 15:38:36 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Fixed packet processing on slow links.  Partial packets were
diff --git a/README b/README
index 520601e3c739cab86b98506ac0983b04c18990f3..da6a575df12abb756270da6a78f890a3cb593923 100644 (file)
--- a/README
+++ b/README
@@ -88,12 +88,21 @@ SILC Commands
                                be provided when joining to the channel.
                c <cipher>      Set/unset channel's cipher
                h <hmac>        Set/unset channel's hmac
+               f <-pubkey|<password>
+                               Set/unset channel founder authentication.
+                               Channel founder may set this mode so that
+                               if the client leaves the channel it can
+                               claim the founder rights when it returns
+                               to the channel.  If -pubkey is set then
+                               the authentication will be done using the
+                               client's public key.  You can claim the
+                               founder rights using the CUMODE command.
 
                Multiple modes can be set/unset at once if the modes does not
                require any arguments.  If mode requires an argument then only
                one mode can be set at once.
 
-       /CUMODE <channel> +|-<modes> <nickname>[@<server>]
+       /CUMODE <channel> +|-<modes> <nickname>[@<server>] [-pubkey|<passwd>]
 
                Changes/set user's mode on a channel.  Most of the modes 
                require that the client who changes some client's mode must
@@ -101,26 +110,39 @@ SILC Commands
                user modes are available:
 
                a <nickname>[@<server>]
+
                                Set/unset all modes (cannot be used to set
                                both founder and operator rights, can be used
                                only to remove both modes at once).
-               f <nickname>[@<server>]
-                               Unset channel founder.  Channel founder rights
-                               cannot be set by user (only by server) so this
-                               can be used only to unset the mode.
+
+               f <nickname>[@<server>] [-pubkey|<password>]
+
+                               Set/Unset channel founder.  If the -pubkey
+                               option or <password> is provided then the
+                               client is claiming the founder rights by
+                               providing the channel founder authentication
+                               data.  If the -pubkey is provided then the
+                               authentication is performed using the
+                               client's public key.  If you are channel
+                               founder you can set the channel founder
+                               authentication using CMODE command.
+
                o <nickname>[@<server>]
+
                                Set/unset channel operator.  Requires that 
                                you are channel operator or channel founder.
 
        /UMODE  +|-<modes>
 
-               Sets/unsets user mode.  Currently none of the modes can
-               be set by the user so this command can be merely used to
-               unset some mode.  Following user modes are available:
+               Sets/unsets user mode.  Note that some of the modes the
+               client cannot set itself.  The following user modes are
+               available:
 
                a       Unset all modes
                s       Unset server operator privileges
                r       Unset router operator privileges
+               g       Set/unset to be gone (or use /AWAY command)
+
 
        /MSG    <nickname> <message>
 
diff --git a/TODO b/TODO
index 2c9c5dfcb3d70e123d70e92e6beafbe4c4a1a382..2798813789e52b4a7e69ef6cc1f30722ab5af4a1 100644 (file)
--- a/TODO
+++ b/TODO
@@ -150,28 +150,10 @@ TODO in the protocol before SILC 0.x
          to various security reasons (the server must not trust the
          public keys blindly without third party verification; that's
          why SENDKEY is not for servers).
-       o Define AWAY command to set the indication flag whether the
-         client is present or not.  Do not save the away message to the
-         server though.
-       o Define the channel founder property to be permanent locally in
-         the server so that channel founder can regain its rights even
-         if it disconnects from the server.  Thus, define a new command
-         or channel user mode that can be used to set the channel founder
-         passphrase or public key that can be used in the authentication
-         when regaining the founder rights.
 
  o New features in the KE/auth protocol
    (draft-riikonen-silc-ke-auth-xx.txt):
 
-       o Merge the KE1 and KE2 payloads into one KE payload that has
-         the `signature' field.  Provide it only if the perty is
-         required to do authentication.
-       o Add MUTUAL_AUTH flag to indicate that the party must perform
-         authentication (to sign with their private key).  Initiator
-         may set it to indicate that it can authenticate but responder
-         MAY require for the initiator to do authentication by setting
-         the flag at the KE Start Payload reply phase.  The responder
-         performs authentication always as now as well.
        o Define group exchange support for the SKE so that the SKE
          could be performed among more than two entities.  This is not
          a showstopper and may be defined later.
index 5e3c1332feda4a6454a9475a6fa2fb8c0e000e96..3165b7d86a57afcfc3c8ea2bdc39eb245f01c623 100644 (file)
@@ -522,12 +522,18 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn,
          }
        }
 
-       if (mode)
-         client->ops->say(client, conn, "%s is %s", nickname,
-                          (mode & SILC_UMODE_SERVER_OPERATOR) ?
-                          "Server Operator" :
-                          (mode & SILC_UMODE_ROUTER_OPERATOR) ?
-                          "SILC Operator" : "[Unknown mode]");
+       if (mode) {
+         if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
+             (mode & SILC_UMODE_ROUTER_OPERATOR))
+           client->ops->say(client, conn, "%s is %s", nickname,
+                            (mode & SILC_UMODE_SERVER_OPERATOR) ?
+                            "Server Operator" :
+                            (mode & SILC_UMODE_ROUTER_OPERATOR) ?
+                            "SILC Operator" : "[Unknown mode]");
+
+         if (mode & SILC_UMODE_GONE)
+           client->ops->say(client, conn, "%s is gone", nickname);
+       }
 
        if (idle && nickname)
          client->ops->say(client, conn, "%s has been idle %d %s",
index ef7a4def61939bf3f7e41d013d24d22c5329a078..79aa0f04ed64dbfa2fa942cd9ad76753ce42c121 100644 (file)
@@ -218,6 +218,8 @@ SILC_CLIENT_LCMD_FUNC(away)
   SilcClientConnection conn = cmd->conn;
   SilcClient client = cmd->client;
   SilcClientInternal app = (SilcClientInternal)client->application;
+  unsigned char modebuf[4];
+  SilcBuffer idp, buffer;
 
   if (!cmd->conn) {
     silc_say(client, conn,
@@ -226,6 +228,8 @@ SILC_CLIENT_LCMD_FUNC(away)
   }
 
   if (cmd->argc == 1) {
+    conn->local_entry->mode &= ~SILC_UMODE_GONE;
+
     if (conn->away) {
       silc_free(conn->away->away);
       silc_free(conn->away);
@@ -236,7 +240,8 @@ SILC_CLIENT_LCMD_FUNC(away)
       silc_screen_print_bottom_line(app->screen, 0);
     }
   } else {
-
+    conn->local_entry->mode |= SILC_UMODE_GONE;
+  
     if (conn->away)
       silc_free(conn->away->away);
     else
@@ -249,6 +254,19 @@ SILC_CLIENT_LCMD_FUNC(away)
     silc_screen_print_bottom_line(app->screen, 0);
   }
 
+  /* Send the UMODE command to se myself as gone */
+  idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
+  SILC_PUT32_MSB(conn->local_entry->mode, modebuf);
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_UMODE, 
+                                         ++conn->cmd_ident, 2, 
+                                         1, idp->data, idp->len, 
+                                         2, modebuf, sizeof(modebuf));
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
+                         NULL, 0, NULL, NULL, buffer->data, 
+                         buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  silc_buffer_free(idp);
+
  out:
   silc_client_command_free(cmd);
 }
index 003f0adffa1010394acdfde63fd94adab46a5e8a..c317a5462a2d40c22556cde3dccfad2bcffc3970 100644 (file)
@@ -1508,13 +1508,13 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
+    clients = silc_idlist_get_clients_by_hash(server->local_list, 
+                                             nick, server->md5hash,
+                                             &clients_count);
     if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
+      clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
   }
   
   /* Check global list as well */
@@ -1531,13 +1531,13 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
        }
       }
     } else {
-      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
+      clients = silc_idlist_get_clients_by_hash(server->global_list, 
+                                               nick, server->md5hash,
+                                               &clients_count);
       if (!clients)
-       clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                                 nick, server->md5hash,
-                                                 &clients_count);
+       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                     nick, server_name,
+                                                     &clients_count);
     }
   }
   
@@ -1616,13 +1616,13 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
+    clients = silc_idlist_get_clients_by_hash(server->local_list, 
+                                             nick, server->md5hash,
+                                             &clients_count);
     if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
+      clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
   }
   
   /* If we are router we will check our global list as well. */
@@ -1639,13 +1639,13 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
        }
       }
     } else {
-      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
+      clients = silc_idlist_get_clients_by_hash(server->global_list, 
+                                               nick, server->md5hash,
+                                               &clients_count);
       if (!clients)
-       clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                                 nick, server->md5hash,
-                                                 &clients_count);
+       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                     nick, server_name,
+                                                     &clients_count);
     }
   }
 
@@ -2996,7 +2996,7 @@ SILC_SERVER_CMD_FUNC(join)
       }
     }
 
-    if (!channel) {
+    if (!channel || !channel->id) {
       /* Channel not found */
 
       /* If we are standalone server we don't have a router, we just create 
@@ -3286,10 +3286,12 @@ SILC_SERVER_CMD_FUNC(umode)
    */
 
   if (mask & SILC_UMODE_SERVER_OPERATOR) {
-    /* Cannot operator mode */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
-                                         SILC_STATUS_ERR_PERM_DENIED);
-    goto out;
+    if (!(client->mode & SILC_UMODE_SERVER_OPERATOR)) {
+      /* Cannot operator mode */
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+                                           SILC_STATUS_ERR_PERM_DENIED);
+      goto out;
+    }
   } else {
     if (client->mode & SILC_UMODE_SERVER_OPERATOR)
       /* Remove the server operator rights */
@@ -3297,16 +3299,26 @@ SILC_SERVER_CMD_FUNC(umode)
   }
 
   if (mask & SILC_UMODE_ROUTER_OPERATOR) {
-    /* Cannot operator mode */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
-                                         SILC_STATUS_ERR_PERM_DENIED);
-    goto out;
+    if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+      /* Cannot operator mode */
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+                                           SILC_STATUS_ERR_PERM_DENIED);
+      goto out;
+    }
   } else {
     if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
       /* Remove the router operator rights */
       client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
   }
 
+  if (mask & SILC_UMODE_GONE) {
+    client->mode |= SILC_UMODE_GONE;
+  } else {
+    if (client->mode & SILC_UMODE_GONE)
+      /* Remove the gone status */
+      client->mode &= ~SILC_UMODE_GONE;
+  }
+
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
@@ -3377,6 +3389,16 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
     }
   }
   
+  if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+    if (is_op && !is_fo)
+      return FALSE;
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+  
   return TRUE;
 }
 
@@ -3387,28 +3409,17 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcIDListData idata = (SilcIDListData)client;
   SilcChannelID *channel_id;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer packet, cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask;
   char *cipher = NULL, *hmac = NULL;
-  unsigned int argc, mode_mask, tmp_len, tmp_len2;
+  unsigned int mode_mask, tmp_len, tmp_len2;
   unsigned short ident = silc_command_get_ident(cmd->payload);
 
-  SILC_LOG_DEBUG(("Start"));
-
-  argc = silc_argument_get_arg_num(cmd->args);
-  if (argc < 2) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  if (argc > 8) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
-    goto out;
-  }
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CMODE, cmd, 2, 7);
 
   /* Get Channel ID */
   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
@@ -3652,6 +3663,57 @@ SILC_SERVER_CMD_FUNC(cmode)
     }
   }
 
+  if (mode_mask & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+      if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+       /* Set the founder authentication */
+       SilcAuthPayload auth;
+       
+       tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
+       if (!tmp) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+         goto out;
+       }
+
+       auth = silc_auth_payload_parse(tmp, tmp_len);
+       if (!auth) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+         goto out;
+       }
+
+       /* Save the public key */
+       tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len);
+       silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+       silc_free(tmp);
+       
+       channel->founder_method = silc_auth_get_method(auth);
+
+       if (channel->founder_method == SILC_AUTH_PASSWORD) {
+         tmp = silc_auth_get_data(auth, &tmp_len);
+         channel->founder_passwd = 
+           silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd));
+         memcpy(channel->founder_passwd, tmp, tmp_len);
+         channel->founder_passwd_len = tmp_len;
+       }
+
+       silc_auth_payload_free(auth);
+      }
+    }
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+      if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+       if (channel->founder_key)
+         silc_pkcs_public_key_free(channel->founder_key);
+       if (channel->founder_passwd) {
+         silc_free(channel->founder_passwd);
+         channel->founder_passwd = NULL;
+       }
+      }
+    }
+  }
+
   /* Finally, set the mode */
   channel->mode = mode_mask;
 
@@ -3660,7 +3722,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
                                     SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
                                     cidp->data, cidp->len, 
-                                    tmp_mask, tmp_len,
+                                    tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
                                     hmac, hmac ? strlen(hmac) : 0);
 
@@ -3695,6 +3757,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcIDListData idata = (SilcIDListData)client;
   SilcChannelID *channel_id;
   SilcClientID *client_id;
   SilcChannelEntry channel;
@@ -3702,11 +3765,11 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcChannelClientEntry chl;
   SilcBuffer packet, idp;
   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
-  unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
+  unsigned int target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
   int notify = FALSE;
   unsigned short ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
   /* Get Channel ID */
   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
@@ -3746,13 +3809,6 @@ SILC_SERVER_CMD_FUNC(cumode)
   silc_list_start(channel->user_list);
   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
     if (chl->client == client) {
-      if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
-         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
-       goto out;
-      }
-
       sender_mask = chl->mode;
       break;
     }
@@ -3789,18 +3845,28 @@ SILC_SERVER_CMD_FUNC(cumode)
                                                  client_id, NULL);
   }
 
-  /* Check whether target client is on the channel */
-  if (!silc_server_client_on_channel(target_client, channel)) {
+  if (target_client != client &&
+      !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
+      !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
     goto out;
   }
 
-  /* Get entry to the channel user list */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-    if (chl->client == target_client)
-      break;
+  /* Check whether target client is on the channel */
+  if (target_client != client) {
+    if (!silc_server_client_on_channel(target_client, channel)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+      goto out;
+    }
+
+    /* Get entry to the channel user list */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+      if (chl->client == target_client)
+       break;
+  }
 
   /* 
    * Change the mode 
@@ -3815,10 +3881,46 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
-    /* Cannot promote anyone to channel founder */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NOT_YOU);
-    goto out;
+    /* The client tries to claim the founder rights. */
+    unsigned char *tmp_auth;
+    unsigned int tmp_auth_len, auth_len;
+    void *auth;
+    
+    if (target_client != client) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_NOT_YOU);
+      goto out;
+    }
+
+    if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
+       !channel->founder_key) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_NOT_YOU);
+      goto out;
+    }
+
+    tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
+    if (!tmp_auth) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+
+    auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
+           (void *)channel->founder_passwd : (void *)channel->founder_key);
+    auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+               channel->founder_passwd_len : 0);
+    
+    if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
+                              channel->founder_method, auth, auth_len,
+                              idata->hash, client->id, SILC_ID_CLIENT)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_AUTH_FAILED);
+      goto out;
+    }
+
+    chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+    notify = TRUE;
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
       if (target_client == client) {
@@ -3836,11 +3938,25 @@ SILC_SERVER_CMD_FUNC(cumode)
   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
     /* Promote to operator */
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
+      }
+
       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
+      }
+
       /* Demote to normal user */
       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
@@ -3848,6 +3964,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+  tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
index 53124d40e338119ee307e87448952482e8b6f2c9..79eb2bbeabebbc518b25719608d2e336f2e17d5f 100644 (file)
@@ -613,6 +613,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 {
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
   SilcServer server = cmd->server;
+  SilcIDCacheEntry cache = NULL;
   SilcCommandStatus status;
   SilcChannelID *id;
   SilcClientID *client_id = NULL;
@@ -702,7 +703,8 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   silc_buffer_put(client_mode_list, tmp, len);
 
   /* See whether we already have the channel. */
-  entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+  entry = silc_idlist_find_channel_by_name(server->local_list, 
+                                          channel_name, &cache);
   if (!entry) {
     /* Add new channel */
 
@@ -719,7 +721,21 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
       goto out;
     }
   } else {
-    silc_free(id);
+    /* The entry exists. */
+    if (entry->id)
+      silc_free(entry->id);
+    entry->id = id;
+    cache->id = entry->id;
+
+    /* Remove the founder auth data if the mode is not set but we have
+       them in the entry */
+    if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
+      silc_pkcs_public_key_free(entry->founder_key);
+      if (entry->founder_passwd) {
+       silc_free(entry->founder_passwd);
+       entry->founder_passwd = NULL;
+      }
+    }
   }
 
   if (entry->hmac_name && hmac) {
index ae2757d31b1b32b1a4331ec3d57d4e3f026e4c97..93b66dd89ed0e04bf66343ae9f6ed5a4b0b30008 100644 (file)
@@ -361,6 +361,16 @@ struct SilcClientEntryStruct {
        Default hmac of the channel. If this is NULL then server picks
        the cipher to be used. This can be set at SILC_COMMAND_JOIN.
 
+   SilcPublicKey founder_key
+   SilcAuthMethod founder_method
+   unsigned char *founder_passwd
+   unsigned int founder_passwd_len
+
+       If the SILC_CMODE_FOUNDER_AUTH has been set then these will include
+       the founder's public key, authentication method and the password
+       if the method is SILC_AUTH_PASSWORD.  If it is SILC_AUTH_PUBLIC_KEY
+       then the `founder_passwd' is NULL.
+
    SilcServerEntry router
 
        This is a pointer to the server list. This is the router server 
@@ -395,6 +405,11 @@ struct SilcChannelEntryStruct {
   char *cipher;
   char *hmac_name;
 
+  SilcPublicKey founder_key;
+  SilcAuthMethod founder_method;
+  unsigned char *founder_passwd;
+  unsigned int founder_passwd_len;
+
   unsigned int user_limit;
   unsigned char *passphrase;
   char *invite_list;
index 0b7b0bfd98f33fedc931e1d1ef31140585a94b57..8e50b85741a76a2460185a7ceceef98083ffae33 100644 (file)
@@ -1766,6 +1766,9 @@ void silc_server_new_channel(SilcServer server,
         We also create a new key for the channel. */
       SilcBuffer users = NULL;
 
+      if (!channel->id)
+       channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
+
       if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
        /* They don't match, send CHANNEL_CHANGE notify to the server to
           force the ID change. */
index 43580638644d0b7592c771018526f466d114e4e0..cea428ca50164802dec07327ac020aec9b868d6d 100644 (file)
@@ -102,6 +102,10 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
     idata->receive_key->set_iv(idata->receive_key, keymat->receive_iv);
   }
 
+  /* Save the remote host's public key */
+  silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, 
+                             ske->ke1_payload->pk_len, &idata->public_key);
+
   /* Save the hash */
   if (!silc_hash_alloc(hash->hash->name, &idata->hash)) {
     silc_cipher_free(idata->send_key);
@@ -187,7 +191,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
           properties packet from initiator. */
        status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
                                          silc_version_string,
-                                         ctx->packet->buffer, NULL, NULL);
+                                         ctx->packet->buffer, FALSE,
+                                         NULL, NULL);
       } else {
        SilcSKEStartPayload *start_payload;
 
@@ -269,7 +274,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
           the initiator. This also creates our parts of the Diffie
           Hellman algorithm. */
        status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, 
-                                           NULL, NULL);
+                                           NULL, NULL, NULL, NULL);
       } else {
        /* Call the Phase-2 function. This creates Diffie Hellman
           key exchange parameters and sends our public part inside
@@ -277,6 +282,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        status = 
          silc_ske_initiator_phase_2(ctx->ske,
                                     server->public_key,
+                                    server->private_key,
                                     silc_server_protocol_ke_send_packet,
                                     context);
       }
index 1e63e429fa0a09f65315830926f5043e6a9d2264..64e70fd16d7597710460572b33e2a9f8f6a445fb 100644 (file)
@@ -715,7 +715,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
     silc_protocol_free(protocol);
     silc_ske_free_key_material(ctx->keymat);
@@ -847,7 +848,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
@@ -1710,8 +1712,8 @@ void silc_server_packet_parse_type(SilcServer server,
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
-    if (sock->protocol && sock->protocol->protocol->type 
-       == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+    if (sock->protocol && sock->protocol->protocol &&
+       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
 
       SilcServerKEInternalContext *proto_ctx = 
        (SilcServerKEInternalContext *)sock->protocol->context;
@@ -1734,8 +1736,8 @@ void silc_server_packet_parse_type(SilcServer server,
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
-    if (sock->protocol && sock->protocol->protocol->type 
-       == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+    if (sock->protocol && sock->protocol->protocol &&
+       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
 
       SilcServerKEInternalContext *proto_ctx = 
        (SilcServerKEInternalContext *)sock->protocol->context;
@@ -1765,8 +1767,8 @@ void silc_server_packet_parse_type(SilcServer server,
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
 
-    if (sock->protocol && sock->protocol->protocol->type 
-       == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+    if (sock->protocol && sock->protocol->protocol &&
+       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
 
       SilcServerKEInternalContext *proto_ctx = 
        (SilcServerKEInternalContext *)sock->protocol->context;
@@ -2262,9 +2264,26 @@ void silc_server_remove_from_channels(SilcServer server,
     /* Remove channel if there is no users anymore */
     if (server->server_type == SILC_ROUTER &&
        silc_list_count(channel->user_list) < 2) {
+      server->stat.my_channels--;
+
+      if (channel->founder_key) {
+       /* The founder auth data exists, do not remove the channel entry */
+       SilcChannelClientEntry chl2;
+
+       silc_free(channel->id);
+       channel->id = NULL;
+
+       silc_list_start(channel->user_list);
+       while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+         silc_list_del(chl2->client->channels, chl2);
+         silc_list_del(channel->user_list, chl2);
+         silc_free(chl2);
+       }
+       continue;
+      }
+
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
-      server->stat.my_channels--;
       continue;
     }
 
@@ -2292,9 +2311,26 @@ void silc_server_remove_from_channels(SilcServer server,
                                           signoff_message, signoff_message ?
                                           strlen(signoff_message) : 0);
 
+      server->stat.my_channels--;
+
+      if (channel->founder_key) {
+       /* The founder auth data exists, do not remove the channel entry */
+       SilcChannelClientEntry chl2;
+
+       silc_free(channel->id);
+       channel->id = NULL;
+
+       silc_list_start(channel->user_list);
+       while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+         silc_list_del(chl2->client->channels, chl2);
+         silc_list_del(channel->user_list, chl2);
+         silc_free(chl2);
+       }
+       continue;
+      }
+
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
-      server->stat.my_channels--;
       continue;
     }
 
@@ -2386,10 +2422,27 @@ int silc_server_remove_from_one_channel(SilcServer server,
                                           SILC_NOTIFY_TYPE_LEAVE, 1,
                                           clidp->data, clidp->len);
 
+      server->stat.my_channels--;
+      silc_buffer_free(clidp);
+
+      if (channel->founder_key) {
+       /* The founder auth data exists, do not remove the channel entry */
+       SilcChannelClientEntry chl2;
+
+       silc_free(channel->id);
+       channel->id = NULL;
+
+       silc_list_start(channel->user_list);
+       while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+         silc_list_del(chl2->client->channels, chl2);
+         silc_list_del(channel->user_list, chl2);
+         silc_free(chl2);
+       }
+       return FALSE;
+      }
+
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
-      silc_buffer_free(clidp);
-      server->stat.my_channels--;
       return FALSE;
     }
 
index ea28e0f0219f16137e1a175a19458a1578996de9..34dbe96ccdab111e72a374420d4f53f5ce434953 100644 (file)
@@ -77,8 +77,7 @@ Table of Contents
 2 SILC Key Exchange Protocol ....................................  3
   2.1 Key Exchange Payloads .....................................  3
       2.1.1 Key Exchange Start Payload ..........................  4
-      2.1.2 Key Exchange 1 Payload ..............................  7
-      2.1.3 Key Exchange 2 Payload ..............................  9
+      2.1.2 Key Exchange Payload ................................  7
   2.2 Key Exchange Procedure .................................... 10
   2.3 Processing the Key Material ............................... 12
   2.4 SILC Key Exchange Groups .................................. 13
@@ -101,9 +100,8 @@ List of Figures
 
 .nf
 Figure 1:  Key Exchange Start Payload
-Figure 2:  Key Exchange 1 Payload
-Figure 3:  Key Exchange 2 Payload
-Figure 4:  Connection Auth Payload
+Figure 2:  Key Exchange Payload
+Figure 3:  Connection Auth Payload
 
 
 .ti 0
@@ -185,7 +183,7 @@ Following descriptions of these payloads.
 .ti 0
 2.1.1 Key Exchange Start Payload
 
-Key exchange between two entities always begins with a
+Key exchange between two entities always begins with the
 SILC_PACKET_KEY_EXCHANGE packet containing Key Exchange Start Payload.
 Initiator sends the Key Exchange Start Payload to the responder filled with
 all security properties it supports.  The responders then checks whether
@@ -296,16 +294,16 @@ o Flags (1 byte) - Indicates flags to be used in the key
   exchange.  Several flags can be set at once by ORing the
   flags together.  Following flags are reserved for this field.
 
-     No flags              0x00
+     No flags                 0x00
 
        In this case the field is ignored.
 
-     No Reply              0x01
+     No Reply                 0x01
 
        If set the receiver of the payload does not reply to 
        the packet.
 
-     PFS                   0x02
+     PFS                      0x02
 
        Perfect Forward Secrecy (PFS) to be used in the
        key exchange protocol.  If not set, re-keying
@@ -316,6 +314,16 @@ o Flags (1 byte) - Indicates flags to be used in the key
        Rest of the flags are reserved for the future and
        must not be set.
 
+     Mutual Authentication    0x04
+
+       Both of the parties will perform authenetication
+       by providing signed data for the other party to
+       verify.  By default, only responder will provide
+       the signature data.  If this is set then the
+       inititator must also provide it.  Initiator may
+       set this but also responder may set this even if
+       initiator did not set it.
+
 o Payload Length (2 bytes) - Length of the entire Key Exchange
   Start payload, not including any other field.
 
@@ -374,35 +382,27 @@ o Compression Algorithms (variable length) - The list of
 
 
 .ti 0
-2.1.2 Key Exchange 1 Payload
-
-Key Exchange 1 Payload is used to deliver computed public data from 
-initiator to responder.  This data is used to compute the shared secret,
-later by all parties.  Key Exchange 1 Payload is only sent after the 
-SILC_PACKET_KEY_EXCHANGE packet and the Key Exchange Start Payload has
-been processed by all the parties.
-
-This payload sends the initiator's public key to the responder.  Responder
-may need the public key in which case it should be checked to be trusted
-by the responder.
-The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_1 packet.
-It must not be sent in any other packet type.  Following diagram 
-represent the Key Exchange 1 Payload.
-
-
-
-
-
-
-
-
-
-
+2.1.2 Key Exchange Payload
 
+Key Exchange payload is used to deliver the public key (or certificate),
+the computed Diffie-Hellman public value and possibly signature data
+from one party to the other.  When initiator is using this payload
+and the Mutual Authentication flag is not set then the initiator must
+not provide the signature data.  If the flag is set then the initiator
+must provide the signature data so that the responder may verify it.
 
+The Mutual Authentication flag is usually used only if a separate
+authentication protocol will not be executed for the initiator of the
+prtocool.  This is case for example when the SKE is performed between
+two SILC clients.  In normal case, where client is connecting to the
+server or server is connecting to the router the Mutual Authentication
+flag is not necessary.
 
+This payload is sent inside SILC_PACKET_KEY_EXCHANGE_1 and inside
+SILC_PACKET_KEY_EXCHANGE_2 packet types.  The initiator uses the 
+SILC_PACKET_KEY_EXCHANGE_1 and the responder the latter.
 
+The following diagram represent the Key Exchange 1 Payload.
 
 
 .in 5
@@ -413,19 +413,25 @@ represent the Key Exchange 1 Payload.
 |       Public Key Length       |        Public Key Type        |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
-~            Public Key of the Host (or certificate)            ~
+~            Public Key of the party (or certificate)           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Data Length      |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Public Data                          ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-|      Public Data Length       |                               |
+|        Signature Length       |                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
 |                                                               |
-~                 Public Data (e = g ^ x mod p)                 ~
+~                        Signature Data                         ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 .in 3
 
 .ce
-Figure 2:  Key Exchange Payload
+Figure 2:  Key Exchange Payload
 
 
 .in 6
@@ -452,92 +458,29 @@ o Public Key Type (2 bytes) - The public key (or certificate)
   sending SILC_PACKET_FAILURE message and the connection should
   be closed immediately.
 
-o Public Data Length (2 bytes) - The length of the public
-  data computed by the responder, not including any other
-  field.
+o Public Data Length (2 bytes) - The length of the Public Data
+  field, not including any other field.
 
 o Public Data (variable length) - The public data to be
-  sent to the responder.  See section 2.2 Key Exchange 
+  sent to the receiver.  See section 2.2 Key Exchange 
   Procedure for detailed description how this field is
   computed.  This value is binary encoded.
-.in 3
-
-
-.ti 0
-2.1.3 Key Exchange 2 Payload
-
-Key Exchange 2 Payload is used to deliver public key, computed public
-data and signature from responder to initiator.  Initiator uses these
-public parts of the key exchange protocol to compute the shared secret.
-
-The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_2 packet.
-It must not be sent in any other packet type.  Following diagram 
-represent the Key Exchange 2 Payload.
-
-
-
-.in 5
-.nf
-                     1                   2                   3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-|       Public Key Length       |        Public Key Type        |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-|                                                               |
-~            Public Key of the Host (or certificate)            ~
-|                                                               |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-|       Public Data Length      |                               |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
-|                                                               |
-~                 Public Data (f = g ^ y mod p)                 ~
-|                                                               |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-|        Signature Length       |                               |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
-|                                                               |
-~                        Signature Data                         ~
-|                                                               |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-.in 3
-
-.ce
-Figure 3:  Key Exchange 2 Payload
-
-
-
-.in 6
-o Public Key Length (2 bytes) - The length of the Public Key
-  (or certificate) field, not including any other field.
-
-o Public Key Type (2 bytes) - The public key (or certificate) 
-  type.  This field indicates the type of the public key in 
-  the packet.  See previous sections for defined public key
-  types.
-
-o Public Key of the host (variable length) - The public
-  key of the sender (or its certificate).  This is verified
-  by the receiver of the packet.  The type of this field
-  is indicated by previous Public Key Type field.
-
-o Public Data Length (2 bytes) - The length of the public
-  data computed by the responder, not including any other
-  field.
-
-o Public Data (variable length) - The public data computed
-  by the responder.  See section 2.2 Key Exchange Procedure
-  for detailed description how this field is computed.  This
-  value is binary encoded.
 
 o Signature Length (2 bytes) - The length of the signature,
   not including any other field.
 
 o Signature Data (variable length) - The signature signed
-  by the responder.  The receiver of this signature must
+  by the sender.  The receiver of this signature must
   verify it.  The verification is done using the public
   key received in this same payload.  See section 2.2
   Key Exchange Procedure for detailed description how
-  to produce the signature.
+  to produce the signature.  If the Mutual Authentication
+  flag is not set then initiator must not provide this
+  field and the Signature Length field must be set to zero (0)
+  value.  If the flag is set then also the initiator must
+  provide this field.  The responder always provides this
+  field.
+.in 3
 
 
 .ti 0
@@ -558,26 +501,45 @@ Setup:  p is a large and public safe prime.  This is one of the
 
     1.  Initiator generates a random number x, where 1 < x < q, 
         and computes e = g ^ x mod p.  The result e is then 
-        encoded into Key Exchange 1 Payload and sent
-        to the responder.
+        encoded into Key Exchange Payload and sent to the
+        responder.
 
+        If the Mutual Authentication flag is set then initiator
+        must also produce signature data SIGN_i which the responder
+        will verify.  The initiator must compute a hash value
+        HASH_i = hash(Key Exchange Start Payload | public key
+        (or certificate) | e).  It then signs the HASH_i value with
+        its private key resulting a signature SIGN_i.
 
     2.  Responder generates a random number y, where 1 < y < q,
         and computes f = g ^ y mod p.  It then computes the
         shared secret KEY = e ^ y mod p, and, a hash value 
-        HASH = hash(Key Exchange Start Payload data | Host public 
+        HASH = hash(Key Exchange Start Payload data | public 
         key (or certificate) | e | f | KEY).  It then signs
         the HASH value with its private key resulting a signature
         SIGN.  
 
         It then encodes its public key (or certificate), f and 
-        SIGN into Key Exchange Payload and sends it to the 
+        SIGN into Key Exchange Payload and sends it to the 
         initiator.
 
+        If the Mutual Authentication flag is set then the responder
+        should verify that the public key provided in the payload
+        is authentic, or if certificates are used it verifies the
+        certificate.  The responder may accept the public key without
+        verifying it, however, doing so may result to insecure key
+        exchange (accepting the public key without verifying may be
+        desirable for practical reasons on many environments.  For
+        long term use this is never desirable, in which case
+        certificates would be the preferred method to use).  It then
+        computes the HASH_i value the same way initiator did in the
+        phase 1.  It then verifies the signature SIGN_i from the
+        payload with the hash value HASH_i using the received public
+        key.
 
     3.  Initiator verifies that the public key provided in
         the payload is authentic, or if certificates are used
-        it verifies the certificate.  Initiator may accept
+        it verifies the certificate.  The initiator may accept
         the public key without verifying it, however, doing
         so may result to insecure key exchange (accepting the
         public key without verifying may be desirable for 
@@ -605,6 +567,9 @@ used.  The key material is also used to produce other security parameters
 later used in the communication.  See section 2.3 Processing the Key
 Material for detailed description how to process the key material.
 
+If the Mutual Authentication flag was set the protocol produces also
+a hash value HASH_i.  This value, however, must be discarded.
+
 After the keys are processed the protocol is ended by sending the
 SILC_PACKET_SUCCESS packet.  Both entities send this packet to 
 each other.  After this both parties will start using the new keys.
@@ -619,8 +584,7 @@ Key Exchange protocol produces secret shared key material KEY.  This
 key material is used to derive the actual keys used in the encryption
 of the communication channel.  The key material is also used to derive
 other security parameters used in the communication.  Key Exchange
-protocol produces a hash value HASH as well.  This is used in the key
-deriving process as a session identifier.
+protocol produces a hash value HASH as well.
 
 Keys are derived from the key material as follows:
 
@@ -925,7 +889,7 @@ represent the Connection Auth Payload.
 .in 3
  
 .ce
-Figure 4:  Connection Auth Payload
+Figure 3:  Connection Auth Payload
 
 
 .in 6
index 09e03cee32cb8b9b81405ac4342d58882a269873..854a0376631ea92b626678491966f1fc81d10320 100644 (file)
@@ -2661,6 +2661,7 @@ List of all defined commands in SILC follows.
               privileges by SILC_COMMAND_SILCOPER command.  Client
               may unset the mode itself.
 
+
         Reply messages to the command:
 
         Max Arguments:  2
index dd4e6472a4b03e94252bc695ec187cc13ac803aa..40508c302e087aaac3c8de4818360d1d456308d7 100644 (file)
@@ -2661,6 +2661,11 @@ List of all defined commands in SILC follows.
               privileges by SILC_COMMAND_SILCOPER command.  Client
               may unset the mode itself.
 
+           0x0004    SILC_UMODE_GONE
+
+              Marks that the user is not currently present in the
+              SILC Network.  Client may set and unset this mode.
+
         Reply messages to the command:
 
         Max Arguments:  2
@@ -2686,10 +2691,11 @@ List of all defined commands in SILC follows.
 
    17   SILC_COMMAND_CMODE
 
-        Max Arguments:  6
-            Arguments:  (1) <Channel ID>    (2) <channel mode mask>
-                        (3) [<user limit>]  (4) [<passphrase>]
-                        (5) [<cipher>]      (6) [<hmac>]
+        Max Arguments:  7
+            Arguments:  (1) <Channel ID>      (2) <channel mode mask>
+                        (3) [<user limit>]    (4) [<passphrase>]
+                        (5) [<cipher>]        (6) [<hmac>]
+                        (7) [<auth payload>]
 
         This command is used by client to set or change channel flags on
         a channel.  Channel has several modes that set various properties
@@ -2840,6 +2846,33 @@ List of all defined commands in SILC follows.
               to set/unset this mode.
 
 
+           0x0200    SILC_CMODE_FOUNDER_AUTH
+
+              Channel founder can set this mode to be able to regain
+              channel founder rights even if the client leaves the 
+              channel.  The <auth payload> is the Authentication Payload
+              consisting of the authentication method and authentication
+              data to be used in the authentication.  The server must
+              not accept NONE authentication method.  Also, if the 
+              method is public key authentication the server must not
+              save the authentication data from the payload as the
+              data is different on all authentications.  In this case the
+              server only saves the authentication method.
+
+              Note, that this  mode is effective only in the current server.
+              The client must connect to the same server later to be able
+              to regain the channel founder rights.  The server must save
+              the public key of the channel founder and use that to identify
+              the client who is claiming the channel founder rights.
+              The rights may be claimed by the SILC_CUMODE_FOUNDER 
+              channel user mode using SILC_COMMAND_CUMODE command.  The
+              set authentication data remains valid as long as the channel
+              exists or until the founder unsets this mode.
+
+              Typical implementation would use [+|-]f on user interface
+              to set/unset this mode.
+
+
         To make the mode system work, client must keep the channel mode
         mask locally so that the mode setting and unsetting would work
         without problems.  The client receives the initial channel mode
@@ -2873,9 +2906,9 @@ List of all defined commands in SILC follows.
 
    18   SILC_COMMAND_CUMODE
 
-        Max Arguments:  3
-            Arguments:  (1) <Channel ID>  (2) <mode mask>
-                        (3) <Client ID>
+        Max Arguments:  4
+            Arguments:  (1) <Channel ID>    (2) <mode mask>
+                        (3) <Client ID>     (4) [<auth payload>]
 
         This command is used by client to change channel user modes on
         channel.  Users on channel may have some special modes and this
@@ -2899,10 +2932,13 @@ List of all defined commands in SILC follows.
 
            0x0001    SILC_CUMODE_FOUNDER
 
-              The client is channel founder of the channel.  This mode
-              cannot be set by other client, it is set by the server when
-              the channel was founded (created).  The mode is provided 
-              because client may remove the founder rights from itself.
+              The client is channel founder of the channel.  Usually this
+              mode is set only by the server when the channel was created.
+              However, if the SILC_CMODE_FOUNDER_AUTH channel mode has
+              been set, the client can claim channel founder privileges
+              by providing the <auth payload> that the server will use
+              to authenticate the client.  The client can  remove this
+              mode at any time.
 
 
            0x0002    SILC_CUMODE_OPERATOR
@@ -2934,6 +2970,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CHANNEL_PRIV
             SILC_STATUS_ERR_UNKNOWN_MODE
             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_AUTH_FAILED
 
 
    19   SILC_COMMAND_KICK
index 674c8ce0ca3e9bcee44ba1bf8c72b315b45f1d2b..458a2fcd13110c97f33e4c65fa580054e4e0e181 100644 (file)
@@ -653,14 +653,16 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
       /* If connection is disconnecting already we will finally
         close the connection */
       if (SILC_IS_DISCONNECTING(sock)) {
-       client->ops->disconnect(client, conn);
-       silc_client_close_connection(client, conn);
+       if (sock == conn->sock)
+         client->ops->disconnect(client, conn);
+       silc_client_close_connection(client, sock, conn);
        return;
       }
       
       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
-      client->ops->disconnect(client, conn);
-      silc_client_close_connection(client, conn);
+      if (sock == conn->sock)
+       client->ops->disconnect(client, conn);
+      silc_client_close_connection(client, sock, conn);
       return;
     }
 
@@ -852,8 +854,8 @@ void silc_client_packet_parse_type(SilcClient client,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE:
-    if (sock->protocol && sock->protocol->protocol->type 
-       == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+    if (sock->protocol && sock->protocol->protocol && 
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
       SilcClientKEInternalContext *proto_ctx = 
        (SilcClientKEInternalContext *)sock->protocol->context;
 
@@ -876,8 +878,8 @@ void silc_client_packet_parse_type(SilcClient client,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE_1:
-    if (sock->protocol && sock->protocol->protocol->type 
-       == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+    if (sock->protocol && sock->protocol->protocol && 
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
       SilcClientKEInternalContext *proto_ctx = 
        (SilcClientKEInternalContext *)sock->protocol->context;
 
@@ -900,8 +902,8 @@ void silc_client_packet_parse_type(SilcClient client,
     }
     break;
   case SILC_PACKET_KEY_EXCHANGE_2:
-    if (sock->protocol && sock->protocol->protocol->type 
-       == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+    if (sock->protocol && sock->protocol->protocol && 
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
       SilcClientKEInternalContext *proto_ctx = 
        (SilcClientKEInternalContext *)sock->protocol->context;
 
@@ -1055,12 +1057,23 @@ void silc_client_packet_send(SilcClient client,
 }
 
 /* Closes connection to remote end. Free's all allocated data except
-   for some information such as nickname etc. that are valid at all time. */
+   for some information such as nickname etc. that are valid at all time. 
+   If the `sock' is NULL then the conn->sock will be used.  If `sock' is
+   provided it will be checked whether the sock and `conn->sock' are the
+   same (they can be different, ie. a socket can use `conn' as its
+   connection but `conn->sock' might be actually a different connection
+   than the `sock'). */
 
 void silc_client_close_connection(SilcClient client,
+                                 SilcSocketConnection sock,
                                  SilcClientConnection conn)
 {
-  SilcSocketConnection sock = conn->sock;
+  int del = FALSE;
+
+  if (!sock || (sock && conn->sock == sock))
+    del = TRUE;
+  if (!sock)
+    sock = conn->sock;
 
   /* We won't listen for this connection anymore */
   silc_schedule_unset_listen_fd(sock->sock);
@@ -1072,13 +1085,13 @@ void silc_client_close_connection(SilcClient client,
   /* Close the actual connection */
   silc_net_close_connection(sock->sock);
 
-  client->ops->say(client, sock->user_data,
-                  "Closed connection to host %s", sock->hostname);
-
   /* Free everything */
-  if (sock->user_data) {
+  if (del && sock->user_data) {
     /* XXX Free all client entries and channel entries. */
 
+    client->ops->say(client, sock->user_data,
+                    "Closed connection to host %s", sock->hostname);
+
     /* Clear ID caches */
     silc_idcache_del_all(conn->client_cache);
     silc_idcache_del_all(conn->channel_cache);
@@ -1145,7 +1158,7 @@ void silc_client_disconnected_by_server(SilcClient client,
   silc_free(msg);
 
   SILC_SET_DISCONNECTED(sock);
-  silc_client_close_connection(client, sock->user_data);
+  silc_client_close_connection(client, sock, sock->user_data);
 }
 
 /* Received error message from server. Display it on the screen. 
@@ -1360,6 +1373,9 @@ char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
     strncat(string, "a", 1);
 
+  if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
+    strncat(string, "f", 1);
+
   if (mode & SILC_CHANNEL_MODE_CIPHER) {
     char cipher[30];
     memset(cipher, 0, sizeof(cipher));
index 150236a76486e8e4ce63bb988033f7d5193fb377..d919965482cab898a8c8141221793611e9bfe99c 100644 (file)
@@ -70,12 +70,13 @@ struct SilcClientConnectionStruct {
   /*
    * Common data 
    */
-  /* Keys */
+  /* Keys and stuff negotiated in the SKE protocol */
   SilcCipher send_key;
   SilcCipher receive_key;
   SilcHmac hmac;
   unsigned char *hmac_key;
   unsigned int hmac_key_len;
+  SilcHash hash;
 
   /* Client ID and Channel ID cache. Messages transmitted in SILC network
      are done using different unique ID's. These are the cache for
index f22960068ac369db41d0e5399dcb0a174311df4d..a97cdc0d951780c4d16f73c2c2464a6373bc59f6 100644 (file)
@@ -671,7 +671,7 @@ SILC_TASK_CALLBACK(silc_client_command_quit_cb)
 
   /* Close connection */
   q->client->ops->disconnect(q->client, q->conn);
-  silc_client_close_connection(q->client, q->conn->sock->user_data);
+  silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
 
   silc_free(q);
 }
@@ -1071,6 +1071,12 @@ SILC_CLIENT_CMD_FUNC(umode)
       else
        mode &= ~SILC_UMODE_ROUTER_OPERATOR;
       break;
+    case 'g':
+      if (add)
+       mode |= SILC_UMODE_GONE;
+      else
+       mode &= ~SILC_UMODE_GONE;
+      break;
     default:
       COMMAND_ERROR;
       goto out;
@@ -1108,7 +1114,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
-  SilcBuffer buffer, chidp;
+  SilcBuffer buffer, chidp, auth = NULL;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   unsigned int mode, add, type, len, arg_len = 0;
   int i;
@@ -1234,6 +1240,28 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode &= ~SILC_CHANNEL_MODE_HMAC;
       }
       break;
+    case 'f':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
+       type = 7;
+
+       if (!strcasecmp(cmd->argv[3], "-pubkey")) {
+         auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                                   cmd->client->private_key,
+                                                   conn->hash,
+                                                   conn->local_id,
+                                                   SILC_ID_CLIENT);
+       } else {
+         auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                         cmd->argv[3], cmd->argv_lens[3]);
+       }
+
+       arg = auth->data;
+       arg_len = auth->len;
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
+      }
+      break;
     default:
       COMMAND_ERROR;
       goto out;
@@ -1268,6 +1296,8 @@ SILC_CLIENT_CMD_FUNC(cmode)
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
+  if (auth)
+    silc_buffer_free(auth);
 
   /* Notify application */
   COMMAND;
@@ -1285,7 +1315,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   SilcChannelEntry channel;
   SilcChannelUser chu;
   SilcClientEntry client_entry;
-  SilcBuffer buffer, clidp, chidp;
+  SilcBuffer buffer, clidp, chidp, auth = NULL;
   unsigned char *name, *cp, modebuf[4];
   unsigned int mode = 0, add, len;
   char *nickname = NULL, *server = NULL;
@@ -1378,10 +1408,23 @@ SILC_CLIENT_CMD_FUNC(cumode)
       }
       break;
     case 'f':
-      if (add)
+      if (add) {
+       if (cmd->argc == 5) {
+         if (!strcasecmp(cmd->argv[4], "-pubkey")) {
+         auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                                   cmd->client->private_key,
+                                                   conn->hash,
+                                                   conn->local_id,
+                                                   SILC_ID_CLIENT);
+         } else {
+           auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                           cmd->argv[4], cmd->argv_lens[4]);
+         }
+       }
        mode |= SILC_CHANNEL_UMODE_CHANFO;
-      else
+      } else {
        mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+      }
       break;
     case 'o':
       if (add)
@@ -1402,16 +1445,20 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4
                                          1, chidp->data, chidp->len, 
                                          2, modebuf, 4,
-                                         3, clidp->data, clidp->len);
-
+                                         3, clidp->data, clidp->len,
+                                         4, auth ? auth->data : NULL, 
+                                         auth ? auth->len : 0);
+  
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
   silc_buffer_free(clidp);
+  if (auth)
+    silc_buffer_free(auth);
   
   /* Notify application */
   COMMAND;
@@ -1990,7 +2037,10 @@ SILC_CLIENT_CMD_FUNC(users)
          strcat(line, " ");
       }
 
-      strncat(line, "  H", 3);
+      if (e->mode & SILC_UMODE_GONE)
+       strcat(line, "  G");
+      else
+       strcat(line, "  H");
       strcat(tmp, m ? m : "");
       strncat(line, tmp, strlen(tmp));
 
index f719bb5742c09262254abb856a11652603d28c76..16124421af678bb091c334f1bbb3133e7c307889 100644 (file)
@@ -117,6 +117,9 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
   /* Save HMAC key to be used in the communication. */
   silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac);
   silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
+
+  /* Save the HASH function */
+  silc_hash_alloc(hash->hash->name, &conn->hash);
 }
 
 /* Checks the version string of the server. */
@@ -183,7 +186,8 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           properties packet from initiator. */
        status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
                                          silc_version_string,
-                                         ctx->packet->buffer, NULL, NULL);
+                                         ctx->packet->buffer, TRUE,
+                                         NULL, NULL);
       } else {
        SilcSKEStartPayload *start_payload;
 
@@ -265,16 +269,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           the initiator. This also creates our parts of the Diffie
           Hellman algorithm. */
        status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, 
-                                           NULL, NULL);
+                                           ctx->verify, context, NULL, NULL);
       } else {
        /* Call the Phase-2 function. This creates Diffie Hellman
           key exchange parameters and sends our public part inside
           Key Exhange 1 Payload to the responder. */
-       status = 
-         silc_ske_initiator_phase_2(ctx->ske,
-                                    client->public_key,
-                                    ctx->send_packet,
-                                    context);
+       status = silc_ske_initiator_phase_2(ctx->ske,
+                                           client->public_key,
+                                           client->private_key,
+                                           ctx->send_packet,
+                                           context);
       }
 
       if (status != SILC_SKE_STATUS_OK) {
index bdf210bb9c7aee8b9d7a3a51c51593ed1dcd184b..4dc56d03e4f172c7383075454f3fa92004a436eb 100644 (file)
@@ -285,8 +285,14 @@ int silc_client_start_key_exchange(SilcClient client,
                                    int fd);
 
 /* Closes connection to remote end. Free's all allocated data except
-   for some information such as nickname etc. that are valid at all time. */
+   for some information such as nickname etc. that are valid at all time. 
+   If the `sock' is NULL then the conn->sock will be used.  If `sock' is
+   provided it will be checked whether the sock and `conn->sock' are the
+   same (they can be different, ie. a socket can use `conn' as its
+   connection but `conn->sock' might be actually a different connection
+   than the `sock'). */
 void silc_client_close_connection(SilcClient client,
+                                 SilcSocketConnection sock,
                                  SilcClientConnection conn);
 
 
index a7a43c4106da093537ad7e87c4dca6fd365b1a0d..0b8f8c8797cc4d7be4a4faab32884a0bc4498a60 100644 (file)
@@ -40,13 +40,19 @@ struct SilcAuthPayloadStruct {
 
 /* Parses and returns Authentication Payload */
 
-SilcAuthPayload silc_auth_payload_parse(SilcBuffer buffer)
+SilcAuthPayload silc_auth_payload_parse(unsigned char *data,
+                                       unsigned int data_len)
 {
+  SilcBuffer buffer;
   SilcAuthPayload new;
   int ret;
 
   SILC_LOG_DEBUG(("Parsing Authentication Payload"));
 
+  buffer = silc_buffer_alloc(data_len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_put(buffer, data, data_len);
+
   new = silc_calloc(1, sizeof(*new));
 
   /* Parse the payload */
@@ -60,14 +66,18 @@ SilcAuthPayload silc_auth_payload_parse(SilcBuffer buffer)
                             SILC_STR_END);
   if (ret == -1) {
     silc_free(new);
+    silc_buffer_free(buffer);
     return NULL;
   }
 
   if (new->len != buffer->len) {
     silc_auth_payload_free(new);
+    silc_buffer_free(buffer);
     return NULL;
   }
 
+  silc_buffer_free(buffer);
+
   /* If password authentication, random data must not be set */
   if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) {
     silc_auth_payload_free(new);
@@ -90,7 +100,7 @@ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
 
   SILC_LOG_DEBUG(("Encoding Authentication Payload"));
 
-  len = 4 + 4 + random_len + auth_len;
+  len = 2 + 2 + 2 + random_len + 2 + auth_len;
   buffer = silc_buffer_alloc(len);
   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
   silc_buffer_format(buffer,
@@ -122,6 +132,24 @@ void silc_auth_payload_free(SilcAuthPayload payload)
   }
 }
 
+/* Get authentication method */
+
+SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
+{
+  return payload->auth_method;
+}
+
+/* Get the authentication data */
+
+unsigned char *silc_auth_get_data(SilcAuthPayload payload,
+                                 unsigned int *auth_len)
+{
+  if (auth_len)
+    *auth_len = payload->auth_len;
+
+  return payload->auth_data;
+}
+
 /******************************************************************************
 
                            Authentication Routines
@@ -152,7 +180,7 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key,
   }
   id_len = silc_id_get_len(type);
 
-  buf = silc_buffer_alloc(random_len + pk_len);
+  buf = silc_buffer_alloc(random_len + id_len + pk_len);
   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
   silc_buffer_format(buf,
                     SILC_STR_UI_XNSTRING(random, random_len),
@@ -160,7 +188,7 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key,
                     SILC_STR_UI_XNSTRING(pk, pk_len),
                     SILC_STR_END);
   
-  ret = silc_calloc(buf->len, sizeof(*ret));
+  ret = silc_calloc(buf->len + 1, sizeof(*ret));
   memcpy(ret, buf->data, buf->len);
 
   if (ret_len)
@@ -178,11 +206,12 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key,
    and the actual authentication data. Returns NULL on error. */
 
 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
+                                             SilcPrivateKey private_key,
                                              SilcHash hash,
                                              void *id, SilcIdType type)
 {
   unsigned char *random;
-  unsigned char auth_data[32];
+  unsigned char auth_data[1024];
   unsigned int auth_len;
   unsigned char *tmp;
   unsigned int tmp_len;
@@ -208,6 +237,8 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
     silc_free(tmp);
     return NULL;
   }
+  silc_pkcs_public_key_set(pkcs, public_key);
+  silc_pkcs_private_key_set(pkcs, private_key);
 
   /* Compute the hash and the signature. */
   if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
@@ -235,7 +266,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
 }
 
 /* Verifies the authentication data. Returns TRUE if authentication was
-   successfull. */
+   successful. */
 
 int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
                                     SilcPublicKey public_key, SilcHash hash,
@@ -262,6 +293,7 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
     silc_free(tmp);
     return FALSE;
   }
+  silc_pkcs_public_key_set(pkcs, public_key);
 
   /* Verify the authentication data */
   if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
@@ -278,7 +310,7 @@ int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
   silc_free(tmp);
   silc_pkcs_free(pkcs);
 
-  SILC_LOG_DEBUG(("Authentication successfull"));
+  SILC_LOG_DEBUG(("Authentication successful"));
 
   return TRUE;
 }
@@ -293,7 +325,7 @@ int silc_auth_public_key_auth_verify_data(SilcBuffer payload,
   SilcAuthPayload auth_payload;
   int ret;
 
-  auth_payload = silc_auth_payload_parse(payload);
+  auth_payload = silc_auth_payload_parse(payload->data, payload->len);
   if (!auth_payload) {
     SILC_LOG_DEBUG(("Authentication failed"));
     return FALSE;
@@ -333,7 +365,7 @@ int silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
     /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
        arguments are not needed. */
     if (!memcmp(payload->auth_data, auth_data, payload->auth_len)) {
-      SILC_LOG_DEBUG(("Authentication successfull"));
+      SILC_LOG_DEBUG(("Authentication successful"));
       return TRUE;
     }
     break;
@@ -361,23 +393,16 @@ int silc_auth_verify_data(unsigned char *payload, unsigned int payload_len,
                          void *id, SilcIdType type)
 {
   SilcAuthPayload auth_payload;
-  SilcBuffer buffer;
   int ret;
 
-  buffer = silc_buffer_alloc(payload_len);
-  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
-  silc_buffer_put(buffer, payload, payload_len);
-  auth_payload = silc_auth_payload_parse(buffer);
-  if (!auth_payload) {
-    silc_buffer_free(buffer);
+  auth_payload = silc_auth_payload_parse(payload, payload_len);
+  if (!auth_payload)
     return FALSE;
-  }
 
   ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len, 
                         hash, id, type);
 
   silc_auth_payload_free(auth_payload);
-  silc_buffer_free(buffer);
 
   return ret;
 }
index 1e55d264885e8a4514b8388d8c4c15200ac17d2f..3181a0ebeb175d6c0b5b947af97ecc9a2a4e89f9 100644 (file)
@@ -41,14 +41,19 @@ typedef unsigned short SilcAuthMethod;
 #define SILC_AUTH_FAILED      1
 
 /* Prototypes */
-SilcAuthPayload silc_auth_payload_parse(SilcBuffer buffer);
+SilcAuthPayload silc_auth_payload_parse(unsigned char *data,
+                                       unsigned int data_len);
 SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
                                    unsigned char *random_data,
                                    unsigned short random_len,
                                    unsigned char *auth_data,
                                    unsigned short auth_len);
 void silc_auth_payload_free(SilcAuthPayload payload);
+SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload);
+unsigned char *silc_auth_get_data(SilcAuthPayload payload,
+                                 unsigned int *auth_len);
 SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
+                                             SilcPrivateKey private_key,
                                              SilcHash hash,
                                              void *id, SilcIdType type);
 int silc_auth_public_key_auth_verify(SilcAuthPayload payload,
index 9a5c4a08de0480a081d68b0bf4873ef1b17ef4ed..ab42a12fb7cd9749e4b15a8a67a2db5e8758ade7 100644 (file)
 #define SILCMODE_H
 
 /* Channel modes */
-#define SILC_CHANNEL_MODE_NONE        0x0000
-#define SILC_CHANNEL_MODE_PRIVATE     0x0001 /* private channel */
-#define SILC_CHANNEL_MODE_SECRET      0x0002 /* secret channel */
-#define SILC_CHANNEL_MODE_PRIVKEY     0x0004 /* channel has private key */
-#define SILC_CHANNEL_MODE_INVITE      0x0008 /* invite only channel */
-#define SILC_CHANNEL_MODE_TOPIC       0x0010 /* topic setting by operator */
-#define SILC_CHANNEL_MODE_ULIMIT      0x0020 /* user limit set */
-#define SILC_CHANNEL_MODE_PASSPHRASE  0x0040 /* passphrase set */
-#define SILC_CHANNEL_MODE_CIPHER      0x0080 /* sets cipher of the channel */
-#define SILC_CHANNEL_MODE_HMAC        0x0100 /* sets hmac of the channel */
+#define SILC_CHANNEL_MODE_NONE         0x0000
+#define SILC_CHANNEL_MODE_PRIVATE      0x0001 /* private channel */
+#define SILC_CHANNEL_MODE_SECRET       0x0002 /* secret channel */
+#define SILC_CHANNEL_MODE_PRIVKEY      0x0004 /* channel has private key */
+#define SILC_CHANNEL_MODE_INVITE       0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_TOPIC        0x0010 /* topic setting by operator */
+#define SILC_CHANNEL_MODE_ULIMIT       0x0020 /* user limit set */
+#define SILC_CHANNEL_MODE_PASSPHRASE   0x0040 /* passphrase set */
+#define SILC_CHANNEL_MODE_CIPHER       0x0080 /* sets cipher of the channel */
+#define SILC_CHANNEL_MODE_HMAC         0x0100 /* sets hmac of the channel */
+#define SILC_CHANNEL_MODE_FOUNDER_AUTH 0x0200 /* sets founder auth data */
 
 /* User modes on channel */
-#define SILC_CHANNEL_UMODE_NONE       0x0000 /* Normal user */
-#define SILC_CHANNEL_UMODE_CHANFO     0x0001 /* channel founder */
-#define SILC_CHANNEL_UMODE_CHANOP     0x0002 /* channel operator */
+#define SILC_CHANNEL_UMODE_NONE        0x0000 /* Normal user */
+#define SILC_CHANNEL_UMODE_CHANFO      0x0001 /* channel founder */
+#define SILC_CHANNEL_UMODE_CHANOP      0x0002 /* channel operator */
 
 /* SILC modes */
-#define SILC_UMODE_NONE               0x0000 /* Normal SILC user */
-#define SILC_UMODE_SERVER_OPERATOR    0x0001 /* Server operator */
-#define SILC_UMODE_ROUTER_OPERATOR    0x0002 /* Router (SILC) operator */
+#define SILC_UMODE_NONE                0x0000 /* Normal SILC user */
+#define SILC_UMODE_SERVER_OPERATOR     0x0001 /* Server operator */
+#define SILC_UMODE_ROUTER_OPERATOR     0x0002 /* Router (SILC) operator */
+#define SILC_UMODE_GONE                0x0004 /* Client is gone */
 
 #endif
index 3fc2d4c7782cad4c3395aeee1467218ff83d3f39..a5ebf6be46a697f26026bce93ec490b30c8f7ad2 100644 (file)
@@ -230,6 +230,8 @@ int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
   silc_hash_make(hash, src, src_len, hashr);
   hash_len = hash->hash->hash_len;
 
+  SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
+
   ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
   memset(hashr, 0, sizeof(hashr));
 
@@ -252,6 +254,8 @@ int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
   silc_hash_make(hash, data, data_len, hashr);
   hash_len = hash->hash->hash_len;
 
+  SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
+
   ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
                           hashr, hash_len);
   memset(hashr, 0, sizeof(hashr));
index acb4d277666ba1f2450063502372671ceffee423..ea9313f10760585a5c14c522f49ba5685bbbd1e2 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 2000 Pekka Riikonen
+  Copyright (C) 2000 - 2001 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
@@ -93,7 +93,7 @@ silc_ske_payload_start_decode(SilcSKE ske,
   SilcSKEStartPayload *payload;
   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
   unsigned char tmp;
-  int ret, len, len2;
+  int ret;
 
   SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
 
@@ -112,7 +112,18 @@ silc_ske_payload_start_decode(SilcSKE ske,
                                                    payload->cookie_len),
                         SILC_STR_UI16_NSTRING_ALLOC(&payload->version,
                                                     &payload->version_len),
-                        SILC_STR_UI_SHORT(&payload->ke_grp_len),
+                        SILC_STR_UI16_NSTRING_ALLOC(&payload->ke_grp_list,
+                                                    &payload->ke_grp_len),
+                        SILC_STR_UI16_NSTRING_ALLOC(&payload->pkcs_alg_list,
+                                                    &payload->pkcs_alg_len),
+                        SILC_STR_UI16_NSTRING_ALLOC(&payload->enc_alg_list,
+                                                    &payload->enc_alg_len),
+                        SILC_STR_UI16_NSTRING_ALLOC(&payload->hash_alg_list,
+                                                    &payload->hash_alg_len),
+                        SILC_STR_UI16_NSTRING_ALLOC(&payload->hmac_alg_list,
+                                                    &payload->hmac_alg_len),
+                        SILC_STR_UI16_NSTRING_ALLOC(&payload->comp_alg_list,
+                                                    &payload->comp_alg_len),
                         SILC_STR_END);
   if (ret == -1) {
     status = SILC_SKE_STATUS_ERROR;
@@ -131,122 +142,6 @@ silc_ske_payload_start_decode(SilcSKE ske,
     goto err;
   }
 
-  if (payload->ke_grp_len < 1) {
-    SILC_LOG_DEBUG(("Bad payload length"));
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
-    goto err;
-  }
-
-  len2 = len = 1 + 1 + 2 + payload->cookie_len + 2 + payload->version_len + 2;
-  silc_buffer_pull(buffer, len);
-
-  /* Parse group list */
-  ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI_XNSTRING_ALLOC(&payload->ke_grp_list, 
-                                                       payload->ke_grp_len),
-                            SILC_STR_UI_SHORT(&payload->pkcs_alg_len),
-                            SILC_STR_END);
-  if (ret == -1) {
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
-
-  if (payload->pkcs_alg_len < 1) {
-    SILC_LOG_DEBUG(("Bad payload length"));
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
-    goto err;
-  }
-
-  len2 += len = payload->ke_grp_len + 2;
-  silc_buffer_pull(buffer, len);
-
-  /* Parse PKCS alg list */
-  ret = 
-    silc_buffer_unformat(buffer,
-                        SILC_STR_UI_XNSTRING_ALLOC(&payload->pkcs_alg_list, 
-                                                   payload->pkcs_alg_len),
-                        SILC_STR_UI_SHORT(&payload->enc_alg_len),
-                        SILC_STR_END);
-  if (ret == -1) {
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
-
-  if (payload->enc_alg_len < 1) {
-    SILC_LOG_DEBUG(("Bad payload length"));
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
-    goto err;
-  }
-
-  len2 += len = payload->pkcs_alg_len + 2;
-  silc_buffer_pull(buffer, len);
-
-  /* Parse encryption alg list */
-  ret = 
-    silc_buffer_unformat(buffer,
-                        SILC_STR_UI_XNSTRING_ALLOC(&payload->enc_alg_list, 
-                                                   payload->enc_alg_len),
-                        SILC_STR_UI_SHORT(&payload->hash_alg_len),
-                        SILC_STR_END);
-  if (ret == -1) {
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
-
-  if (payload->hash_alg_len < 1) {
-    SILC_LOG_DEBUG(("Bad payload length"));
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
-    goto err;
-  }
-
-  len2 += len = payload->enc_alg_len + 2;
-  silc_buffer_pull(buffer, len);
-
-  /* Parse hash alg list */
-  ret = 
-    silc_buffer_unformat(buffer,
-                        SILC_STR_UI_XNSTRING_ALLOC(&payload->hash_alg_list, 
-                                                   payload->hash_alg_len),
-                        SILC_STR_UI_SHORT(&payload->hmac_alg_len),
-                        SILC_STR_END);
-  if (ret == -1) {
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
-
-  len2 += len = payload->hash_alg_len + 2;
-  silc_buffer_pull(buffer, len);
-
-  /* Parse HMAC list */
-  ret = 
-    silc_buffer_unformat(buffer,
-                        SILC_STR_UI_XNSTRING_ALLOC(&payload->hmac_alg_list, 
-                                                   payload->hmac_alg_len),
-                        SILC_STR_UI_SHORT(&payload->comp_alg_len),
-                        SILC_STR_END);
-  if (ret == -1) {
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
-
-  len2 += len = payload->hmac_alg_len + 2;
-  silc_buffer_pull(buffer, len);
-
-  /* Parse compression alg list */
-  if (payload->comp_alg_len) {
-    ret = 
-      silc_buffer_unformat(buffer,
-                          SILC_STR_UI_XNSTRING_ALLOC(&payload->comp_alg_list, 
-                                                     payload->comp_alg_len),
-                          SILC_STR_END);
-    if (ret == -1) {
-      status = SILC_SKE_STATUS_ERROR;
-      goto err;
-    }
-  }
-
-  silc_buffer_push(buffer, len2);
-
   /* Return the payload */
   *return_payload = payload;
 
@@ -284,169 +179,36 @@ void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
   }
 }
 
-/* Encodes Key Exchange 1 Payload into a SILC Buffer to be sent
-   to the other end. */
+/* Encodes Key Exchange Payload into a SILC Buffer to be sent to the other
+   end. */
 
-SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
-                                         SilcSKEOnePayload *payload,
-                                         SilcBuffer *return_buffer)
+SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
+                                        SilcSKEKEPayload *payload,
+                                        SilcBuffer *return_buffer)
 {
   SilcBuffer buf;
-  unsigned char *e_str;
-  unsigned int e_len;
+  unsigned char *x_str;
+  unsigned int x_len;
   int ret;
 
-  SILC_LOG_DEBUG(("Encoding KE Payload"));
+  SILC_LOG_DEBUG(("Encoding KE Payload"));
 
   if (!payload)
     return SILC_SKE_STATUS_ERROR;
 
-  /* Encode the integer into binary data */
-  e_str = silc_mp_mp2bin(&payload->e, 0, &e_len);
-  if (!e_str)
+  if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL &&
+      !payload->sign_data) {
+    SILC_LOG_DEBUG(("Signature data is missing"));
     return SILC_SKE_STATUS_ERROR;
-
-  /* Allocate channel payload buffer. The length of the buffer
-     is 2 + e. */
-  buf = silc_buffer_alloc(e_len + 2 + payload->pk_len + 2 + 2);
-  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
-
-  /* Encode the payload */
-  ret = silc_buffer_format(buf, 
-                          SILC_STR_UI_SHORT(payload->pk_len),
-                          SILC_STR_UI_SHORT(payload->pk_type),
-                          SILC_STR_UI_XNSTRING(payload->pk_data, 
-                                               payload->pk_len),
-                          SILC_STR_UI_SHORT(e_len),
-                          SILC_STR_UI_XNSTRING(e_str, e_len),
-                          SILC_STR_END);
-  if (ret == -1) {
-    memset(e_str, 'F', e_len);
-    silc_free(e_str);
-    silc_buffer_free(buf);
-    return SILC_SKE_STATUS_ERROR;
-  }
-
-  /* Return encoded buffer */
-  *return_buffer = buf;
-
-  memset(e_str, 'F', e_len);
-  silc_free(e_str);
-
-  return SILC_SKE_STATUS_OK;
-}
-
-/* Parses the Key Exchange 1 Payload. Parsed data is returned
-   to allocated payload structure. */
-
-SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
-                                         SilcBuffer buffer,
-                                         SilcSKEOnePayload **return_payload)
-{
-  SilcSKEOnePayload *payload;
-  SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
-  unsigned char *e;
-  unsigned short e_len;
-  int ret;
-
-  SILC_LOG_DEBUG(("Decoding Key Exchange 1 Payload"));
-
-  SILC_LOG_HEXDUMP(("KE 1 Payload"), buffer->data, buffer->len);
-
-  payload = silc_calloc(1, sizeof(*payload));
-
-  /* Parse start of the payload */
-  ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI_SHORT(&payload->pk_len),
-                            SILC_STR_UI_SHORT(&payload->pk_type),
-                            SILC_STR_END);
-  if (ret == -1) {
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
-                      
-  if (payload->pk_len < 5) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD;
-    goto err;
-  }
-
-  /* Parse public key data */
-  silc_buffer_pull(buffer, 2 + 2);
-  ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
-                                                       payload->pk_len),
-                            SILC_STR_UI16_NSTRING_ALLOC(&e, &e_len),
-                            SILC_STR_END);
-  if (ret == -1) {
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
-
-  if (e_len < 3) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD;
-    goto err;
-  }
-
-  silc_buffer_push(buffer, 2 + 2);
-
-  if (payload->pk_len + 2 + 2 + 2 + e_len != buffer->len) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD;
-    goto err;
-  }
-
-  /* Decode the HEX string to integer */
-  silc_mp_init(&payload->e);
-  silc_mp_bin2mp(e, e_len, &payload->e);
-  memset(e, 0, sizeof(e_len));
-  silc_free(e);
-
-  /* Return the payload */
-  *return_payload = payload;
-
-  return SILC_SKE_STATUS_OK;
-
- err:
-  silc_free(payload);
-  ske->status = status;
-  return status;
-}
-
-/* Free's KE1 Payload */
-
-void silc_ske_payload_one_free(SilcSKEOnePayload *payload)
-{
-  if (payload) {
-    if (payload->pk_data)
-      silc_free(payload->pk_data);
-    silc_free(payload);
   }
-}
 
-/* Encodes Key Exchange 2 Payload into a SILC Buffer to be sent
-   to the other end. */
-
-SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
-                                         SilcSKETwoPayload *payload,
-                                         SilcBuffer *return_buffer)
-{
-  SilcBuffer buf;
-  unsigned char *f_str;
-  unsigned int f_len;
-  unsigned int len;
-  int ret;
-
-  SILC_LOG_DEBUG(("Encoding KE 2 Payload"));
-
-  if (!payload)
-    return SILC_SKE_STATUS_ERROR;
-
-  /* Encode the integer into HEX string */
-  f_str = silc_mp_mp2bin(&payload->f, 0, &f_len);
+  /* Encode the integer into binary data */
+  x_str = silc_mp_mp2bin(&payload->x, 0, &x_len);
 
   /* Allocate channel payload buffer. The length of the buffer
-     is 2 + 2 + public key + 2 + f + 2 + signature. */
-  len = payload->pk_len + 2 + 2 + f_len + 2 + payload->sign_len + 2;
-  buf = silc_buffer_alloc(len);
+     is 4 + public key + 2 + x + 2 + signature. */
+  buf = silc_buffer_alloc(4 + payload->pk_len + 2 + x_len + 
+                         2 + payload->sign_len);
   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
 
   /* Encode the payload */
@@ -455,15 +217,15 @@ SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
                           SILC_STR_UI_SHORT(payload->pk_type),
                           SILC_STR_UI_XNSTRING(payload->pk_data, 
                                                payload->pk_len),
-                          SILC_STR_UI_SHORT(f_len),
-                          SILC_STR_UI_XNSTRING(f_str, f_len),
+                          SILC_STR_UI_SHORT(x_len),
+                          SILC_STR_UI_XNSTRING(x_str, x_len),
                           SILC_STR_UI_SHORT(payload->sign_len),
                           SILC_STR_UI_XNSTRING(payload->sign_data, 
                                                payload->sign_len),
                           SILC_STR_END);
   if (ret == -1) {
-    memset(f_str, 'F', f_len);
-    silc_free(f_str);
+    memset(x_str, 'F', x_len);
+    silc_free(x_str);
     silc_buffer_free(buf);
     return SILC_SKE_STATUS_ERROR;
   }
@@ -471,29 +233,31 @@ SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
   /* Return encoded buffer */
   *return_buffer = buf;
 
-  memset(f_str, 'F', f_len);
-  silc_free(f_str);
+  SILC_LOG_HEXDUMP(("KE Payload"), buf->data, buf->len);
+
+  memset(x_str, 'F', x_len);
+  silc_free(x_str);
 
   return SILC_SKE_STATUS_OK;
 }
 
-/* Parses the Key Exchange 2 Payload. Parsed data is returned
-   to allocated payload structure. */
+/* Parses the Key Exchange Payload. Parsed data is returned to allocated
+   payload structure. */
 
-SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
-                                         SilcBuffer buffer,
-                                         SilcSKETwoPayload **return_payload)
+SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
+                                        SilcBuffer buffer,
+                                        SilcSKEKEPayload **return_payload)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
-  SilcSKETwoPayload *payload;
-  unsigned char *f;
-  unsigned short f_len;
+  SilcSKEKEPayload *payload;
+  unsigned char *x;
+  unsigned short x_len;
   unsigned int tot_len = 0, len2;
   int ret;
 
-  SILC_LOG_DEBUG(("Decoding Key Exchange Payload"));
+  SILC_LOG_DEBUG(("Decoding Key Exchange Payload"));
 
-  SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len);
+  SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len);
 
   payload = silc_calloc(1, sizeof(*payload));
 
@@ -521,7 +285,7 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
   ret = silc_buffer_unformat(buffer,
                             SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
                                                        payload->pk_len),
-                            SILC_STR_UI16_NSTRING_ALLOC(&f, &f_len),
+                            SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len),
                             SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, 
                                                         &payload->sign_len),
                             SILC_STR_END);
@@ -530,15 +294,18 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
     goto err;
   }
 
-  tot_len += f_len + 2;
+  tot_len += x_len + 2;
   tot_len += payload->sign_len + 2;
 
-  if (f_len < 3) {
+  if (x_len < 3) {
     status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
 
-  if (payload->sign_len < 3) {
+  if ((ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
+      (payload->sign_len < 3 || !payload->sign_data)) {
+    SILC_LOG_DEBUG(("The signature data is missing - both parties are "
+                   "required to do authentication"));
     status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
@@ -548,11 +315,11 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
     goto err;
   }
   
-  /* Decode the HEX string to integer */
-  silc_mp_init(&payload->f);
-  silc_mp_bin2mp(f, f_len, &payload->f);
-  memset(f, 0, sizeof(f_len));
-  silc_free(f);
+  /* Decode the binary data to integer */
+  silc_mp_init(&payload->x);
+  silc_mp_bin2mp(x, x_len, &payload->x);
+  memset(x, 0, sizeof(x_len));
+  silc_free(x);
 
   /* Return the payload */
   *return_payload = payload;
@@ -569,13 +336,14 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
   return status;
 }
 
-/* Free's KE2 Payload */
+/* Free's KE Payload */
 
-void silc_ske_payload_two_free(SilcSKETwoPayload *payload)
+void silc_ske_payload_ke_free(SilcSKEKEPayload *payload)
 {
   if (payload) {
     if (payload->pk_data)
       silc_free(payload->pk_data);
+    silc_mp_clear(&payload->x);
     if (payload->sign_data)
       silc_free(payload->sign_data);
     silc_free(payload);
index fa88e4155acec2b21d6cc9800dbf28089cce74d3..df982a7bca3d416b9a889f079a59620ec11597c8 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 2000 Pekka Riikonen
+  Copyright (C) 2000 - 2001 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
@@ -33,19 +33,12 @@ silc_ske_payload_start_decode(SilcSKE ske,
                              SilcBuffer buffer,
                              SilcSKEStartPayload **return_payload);
 void silc_ske_payload_start_free(SilcSKEStartPayload *payload);
-SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
-                                         SilcSKEOnePayload *payload,
-                                         SilcBuffer *return_buffer);
-SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
-                                         SilcBuffer buffer,
-                                         SilcSKEOnePayload **return_payload);
-void silc_ske_payload_one_free(SilcSKEOnePayload *payload);
-SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
-                                         SilcSKETwoPayload *payload,
-                                         SilcBuffer *return_buffer);
-SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
-                                         SilcBuffer buffer,
-                                         SilcSKETwoPayload **return_payload);
-void silc_ske_payload_two_free(SilcSKETwoPayload *payload);
+SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
+                                        SilcSKEKEPayload *payload,
+                                        SilcBuffer *return_buffer);
+SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
+                                        SilcBuffer buffer,
+                                        SilcSKEKEPayload **return_payload);
+void silc_ske_payload_ke_free(SilcSKEKEPayload *payload);
 
 #endif
index 56bf497af7365e1dfb0bafca508a10e8aafc9020..d6cc162edb172b5052b696fbc35e23884cd8c2f6 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 2000 Pekka Riikonen
+  Copyright (C) 2000 - 2001 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
@@ -51,25 +51,16 @@ typedef struct {
   unsigned char *comp_alg_list;
 } SilcSKEStartPayload;
 
-/* SILC Key Exchange Payload */
+/* SILC Key Exchange Payload */
 typedef struct {
   unsigned short pk_len;
   unsigned char *pk_data;
   unsigned short pk_type;
 
-  SilcInt e;
-} SilcSKEOnePayload;
-
-/* SILC Key Exchange 2 Payload */
-typedef struct {
-  unsigned short pk_len;
-  unsigned char *pk_data;
-  unsigned short pk_type;
-
-  SilcInt f;
+  SilcInt x;
 
   unsigned short sign_len;
   unsigned char *sign_data;
-} SilcSKETwoPayload;
+} SilcSKEKEPayload;
 
 #endif
index e8e777a41351515fbe1050c9f1df6e7e47a78c1d..978739224bed989658ad40d099649f9a90e52739 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 2000 Pekka Riikonen
+  Copyright (C) 2000 - 2001 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
@@ -48,13 +48,9 @@ void silc_ske_free(SilcSKE ske)
     if (ske->start_payload)
       silc_ske_payload_start_free(ske->start_payload);
 
-    /* Free KE1 payload */
+    /* Free KE payload */
     if (ske->ke1_payload)
-      silc_ske_payload_one_free(ske->ke1_payload);
-
-    /* Free KE2 payload */
-    if (ske->ke2_payload)
-      silc_ske_payload_two_free(ske->ke2_payload);
+      silc_ske_payload_ke_free(ske->ke1_payload);
 
     /* Free rest */
     if (ske->prop) {
@@ -222,17 +218,18 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
 
 /* This function creates random number x, such that 1 < x < q and 
    computes e = g ^ x mod p and sends the result to the remote end in 
-   Key Exchange Payload. */
+   Key Exchange Payload. */
 
 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
                                         SilcPublicKey public_key,
+                                        SilcPrivateKey private_key,
                                         SilcSKESendPacketCb send_packet,
                                         void *context)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer payload_buf;
   SilcInt *x, e;
-  SilcSKEOnePayload *payload;
+  SilcSKEKEPayload *payload;
   unsigned int pk_len;
 
   SILC_LOG_DEBUG(("Start"));
@@ -257,10 +254,15 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   silc_mp_init(&e);
   silc_mp_powm(&e, &ske->prop->group->generator, x, 
               &ske->prop->group->group);
-  
-  /* Encode the result to Key Exchange 1 Payload. */
+
+  /* Encode the result to Key Exchange Payload. */
+
   payload = silc_calloc(1, sizeof(*payload));
-  payload->e = e;
+  ske->ke1_payload = payload;
+
+  payload->x = e;
+
+  /* Get public key */
   payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
   if (!payload->pk_data) {
     silc_mp_clear(x);
@@ -272,7 +274,32 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   }
   payload->pk_len = pk_len;
   payload->pk_type = SILC_SKE_PK_TYPE_SILC;
-  status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
+
+  /* Compute signature data if we are doing mutual authentication */
+  if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+    unsigned char hash[32], sign[1024];
+    unsigned int hash_len, sign_len;
+
+    SILC_LOG_DEBUG(("We are doing mutual authentication"));
+    SILC_LOG_DEBUG(("Computing HASH value"));
+
+    /* Compute the hash value */
+    memset(hash, 0, sizeof(hash));
+    silc_ske_make_hash(ske, hash, &hash_len, TRUE);
+
+    SILC_LOG_DEBUG(("Signing HASH_i value"));
+    
+    /* Sign the hash value */
+    silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
+                                  private_key->prv_len);
+    silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
+    payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
+    memcpy(payload->sign_data, sign, sign_len);
+    memset(sign, 0, sizeof(sign));
+    payload->sign_len = sign_len;
+  }
+
+  status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
   if (status != SILC_SKE_STATUS_OK) {
     silc_mp_clear(x);
     silc_free(x);
@@ -283,7 +310,6 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
     return status;
   }
 
-  ske->ke1_payload = payload;
   ske->x = x;
 
   /* Send the packet. */
@@ -295,19 +321,19 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   return status;
 }
 
-/* Receives Key Exchange Payload from responder consisting responders
+/* Receives Key Exchange Payload from responder consisting responders
    public key, f, and signature. This function verifies the public key,
    computes the secret shared key and verifies the signature. */
 
 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
-                                       SilcBuffer ke2_payload,
+                                       SilcBuffer ke_payload,
                                        SilcSKEVerifyCb verify_key,
                                        void *verify_context,
                                        SilcSKECb callback,
                                        void *context)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
-  SilcSKETwoPayload *payload;
+  SilcSKEKEPayload *payload;
   SilcPublicKey public_key = NULL;
   SilcInt *KEY;
   unsigned char hash[32];
@@ -316,7 +342,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   SILC_LOG_DEBUG(("Start"));
 
   /* Decode the payload */
-  status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
+  status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
   if (status != SILC_SKE_STATUS_OK) {
     ske->status = status;
     return status;
@@ -328,7 +354,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   /* Compute the shared secret key */
   KEY = silc_calloc(1, sizeof(*KEY));
   silc_mp_init(KEY);
-  silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group);
+  silc_mp_powm(KEY, &payload->x, ske->x, &ske->prop->group->group);
   ske->KEY = KEY;
 
   SILC_LOG_DEBUG(("Verifying public key"));
@@ -349,7 +375,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   SILC_LOG_DEBUG(("Public key is authentic"));
 
   /* Compute the hash value */
-  status = silc_ske_make_hash(ske, hash, &hash_len);
+  status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
   if (status != SILC_SKE_STATUS_OK)
     goto err;
 
@@ -357,7 +383,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   memcpy(ske->hash, hash, hash_len);
   ske->hash_len = hash_len;
 
-  SILC_LOG_DEBUG(("Verifying signature"));
+  SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
 
   /* Verify signature */
   silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, 
@@ -384,7 +410,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
 
  err:
   memset(hash, 'F', sizeof(hash));
-  silc_ske_payload_two_free(payload);
+  silc_ske_payload_ke_free(payload);
   ske->ke2_payload = NULL;
 
   silc_mp_clear(ske->KEY);
@@ -417,6 +443,7 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
                                       SilcSocketConnection sock,
                                       char *version,
                                       SilcBuffer start_payload,
+                                      int mutual_auth,
                                       SilcSKECb callback,
                                       void *context)
 {
@@ -439,6 +466,12 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
      compute the HASH value. */
   ske->start_payload_copy = silc_buffer_copy(start_payload);
 
+  /* Force the mutual authentication flag if we want to do it. */
+  if (mutual_auth) {
+    SILC_LOG_DEBUG(("Force mutual authentication"));
+    remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
+  }
+
   /* Parse and select the security properties from the payload */
   payload = silc_calloc(1, sizeof(*payload));
   status = silc_ske_select_security_properties(ske, version,
@@ -551,33 +584,87 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
   return status;
 }
 
-/* This function receives the Key Exchange Payload from the initiator.
+/* This function receives the Key Exchange Payload from the initiator.
    After processing the payload this then selects random number x,
    such that 1 < x < q and computes f = g ^ x mod p. This then puts
-   the result f to a Key Exchange Payload which is later processed
+   the result f to a Key Exchange Payload which is later processed
    in ske_responder_finish function. The callback function should
    not touch the payload (it should merely call the ske_responder_finish
    function). */
 
 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
-                                        SilcBuffer ke1_payload,
+                                        SilcBuffer ke_payload,
+                                        SilcSKEVerifyCb verify_key,
+                                        void *verify_context,
                                         SilcSKECb callback,
                                         void *context)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
-  SilcSKEOnePayload *one_payload;
-  SilcSKETwoPayload *two_payload;
+  SilcSKEKEPayload *recv_payload, *send_payload;
   SilcInt *x, f;
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* Decode Key Exchange Payload */
-  status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
+  /* Decode Key Exchange Payload */
+  status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
   if (status != SILC_SKE_STATUS_OK) {
     ske->status = status;
     return status;
   }
 
+  ske->ke1_payload = recv_payload;
+
+  /* Verify the received public key and verify the signature if we are
+     doing mutual authentication. */
+  if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+    SilcPublicKey public_key = NULL;
+    unsigned char hash[32];
+    unsigned int hash_len;
+
+    SILC_LOG_DEBUG(("We are doing mutual authentication"));
+    SILC_LOG_DEBUG(("Verifying public key"));
+    
+    if (!silc_pkcs_public_key_decode(recv_payload->pk_data, 
+                                    recv_payload->pk_len, 
+                                    &public_key)) {
+      status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+      return status;
+    }
+
+    if (verify_key) {
+      status = (*verify_key)(ske, recv_payload->pk_data, recv_payload->pk_len,
+                            recv_payload->pk_type, verify_context);
+      if (status != SILC_SKE_STATUS_OK)
+       return status;
+    }
+
+    SILC_LOG_DEBUG(("Public key is authentic"));
+
+    /* Compute the hash value */
+    status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
+    if (status != SILC_SKE_STATUS_OK)
+      return status;
+
+    SILC_LOG_DEBUG(("Verifying signature"));
+    
+    /* Verify signature */
+    silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, 
+                                 public_key->pk_len);
+    if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, 
+                        recv_payload->sign_len, hash, hash_len) == FALSE) {
+      
+      SILC_LOG_DEBUG(("Signature don't match"));
+      
+      status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
+      return status;
+    }
+    
+    SILC_LOG_DEBUG(("Signature is Ok"));
+    
+    silc_pkcs_public_key_free(public_key);
+    memset(hash, 'F', hash_len);
+  }
+
   /* Create the random number x, 1 < x < q. */
   x = silc_calloc(1, sizeof(*x));
   silc_mp_init(x);
@@ -599,11 +686,10 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
               &ske->prop->group->group);
   
   /* Save the results for later processing */
-  two_payload = silc_calloc(1, sizeof(*two_payload));
-  two_payload->f = f;
+  send_payload = silc_calloc(1, sizeof(*send_payload));
+  send_payload->x = f;
   ske->x = x;
-  ske->ke1_payload = one_payload;
-  ske->ke2_payload = two_payload;
+  ske->ke2_payload = send_payload;
 
   /* Call the callback. */
   if (callback)
@@ -614,7 +700,7 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
 
 /* This function computes the secret shared key KEY = e ^ x mod p, and, 
    a hash value to be signed and sent to the other end. This then
-   encodes Key Exchange Payload and sends it to the other end. */
+   encodes Key Exchange Payload and sends it to the other end. */
 
 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
                                        SilcPublicKey public_key,
@@ -641,7 +727,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   /* Compute the shared secret key */
   KEY = silc_calloc(1, sizeof(*KEY));
   silc_mp_init(KEY);
-  silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x, 
+  silc_mp_powm(KEY, &ske->ke1_payload->x, ske->x, 
               &ske->prop->group->group);
   ske->KEY = KEY;
 
@@ -661,7 +747,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
 
   /* Compute the hash value */
   memset(hash, 0, sizeof(hash));
-  status = silc_ske_make_hash(ske, hash, &hash_len);
+  status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
   if (status != SILC_SKE_STATUS_OK)
     goto err;
 
@@ -680,9 +766,9 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   memset(sign, 0, sizeof(sign));
   ske->ke2_payload->sign_len = sign_len;
 
-  /* Encode the Key Exchange Payload */
-  status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
-                                      &payload_buf);
+  /* Encode the Key Exchange Payload */
+  status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
+                                     &payload_buf);
   if (status != SILC_SKE_STATUS_OK)
     goto err;
 
@@ -698,7 +784,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   silc_mp_clear(ske->KEY);
   silc_free(ske->KEY);
   ske->KEY = NULL;
-  silc_ske_payload_two_free(ske->ke2_payload);
+  silc_ske_payload_ke_free(ske->ke2_payload);
 
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
@@ -1223,11 +1309,15 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
   return status;
 }
 
-/* Creates a hash value HASH as defined in the SKE protocol. */
+/* Creates a hash value HASH as defined in the SKE protocol. If the
+   `initiator' is TRUE then this function is used to create the HASH_i
+   hash value defined in the protocol. If it is FALSE then this is used
+   to create the HASH value defined by the protocol. */
 
 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
                                 unsigned char *return_hash,
-                                unsigned int *return_hash_len)
+                                unsigned int *return_hash_len,
+                                int initiator)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer buf;
@@ -1237,47 +1327,79 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Start"));
 
-  e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len);
-  f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len);
-  KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
-
-  buf = silc_buffer_alloc(ske->start_payload_copy->len + 
-                         ske->pk_len + e_len + f_len + KEY_len);
-  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+  if (initiator == FALSE) {
+    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
+    f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
+    KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
+    
+    buf = silc_buffer_alloc(ske->start_payload_copy->len + 
+                           ske->pk_len + e_len + f_len + KEY_len);
+    silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+    
+    /* Format the buffer used to compute the hash value */
+    ret = 
+      silc_buffer_format(buf,
+                        SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+                                             ske->start_payload_copy->len),
+                        SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
+                        SILC_STR_UI_XNSTRING(e, e_len),
+                        SILC_STR_UI_XNSTRING(f, f_len),
+                        SILC_STR_UI_XNSTRING(KEY, KEY_len),
+                        SILC_STR_END);
+    if (ret == -1) {
+      silc_buffer_free(buf);
+      memset(e, 0, e_len);
+      memset(f, 0, f_len);
+      memset(KEY, 0, KEY_len);
+      silc_free(e);
+      silc_free(f);
+      silc_free(KEY);
+      return SILC_SKE_STATUS_ERROR;
+    }
 
-  /* Format the buffer used to compute the hash value */
-  ret = silc_buffer_format(buf,
-                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
-                                               ske->start_payload_copy->len),
-                          SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
-                          SILC_STR_UI_XNSTRING(e, e_len),
-                          SILC_STR_UI_XNSTRING(f, f_len),
-                          SILC_STR_UI_XNSTRING(KEY, KEY_len),
-                          SILC_STR_END);
-  if (ret == -1) {
-    silc_buffer_free(buf);
     memset(e, 0, e_len);
     memset(f, 0, f_len);
     memset(KEY, 0, KEY_len);
     silc_free(e);
     silc_free(f);
     silc_free(KEY);
-    return SILC_SKE_STATUS_ERROR;
+  } else {
+    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
+
+    buf = silc_buffer_alloc(ske->start_payload_copy->len + 
+                           ske->pk_len + e_len);
+    silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+    
+    /* Format the buffer used to compute the hash value */
+    ret = 
+      silc_buffer_format(buf,
+                        SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+                                             ske->start_payload_copy->len),
+                        SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
+                        SILC_STR_UI_XNSTRING(e, e_len),
+                        SILC_STR_END);
+    if (ret == -1) {
+      silc_buffer_free(buf);
+      memset(e, 0, e_len);
+      silc_free(e);
+      return SILC_SKE_STATUS_ERROR;
+    }
+
+    memset(e, 0, e_len);
+    silc_free(e);
   }
 
   /* Make the hash */
   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
   *return_hash_len = ske->prop->hash->hash->hash_len;
 
-  SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
+  if (initiator == FALSE) {
+    SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
+  } else {
+    SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
+  }
 
   silc_buffer_free(buf);
-  memset(e, 0, e_len);
-  memset(f, 0, f_len);
-  memset(KEY, 0, KEY_len);
-  silc_free(e);
-  silc_free(f);
-  silc_free(KEY);
 
   return status;
 }
index 880475e028f2183eed0fc4cbd835f576c2435d84..13e82eb65f68e5f80bfcf54045a880a28832d9e3 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 2000 Pekka Riikonen
+  Copyright (C) 2000 - 2001 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
@@ -77,9 +77,10 @@ typedef struct {
 
 /* Security Property Flags. */
 typedef enum {
-  SILC_SKE_SP_FLAG_NONE      = (1L << 0),
-  SILC_SKE_SP_FLAG_NO_REPLY  = (1L << 1),
-  SILC_SKE_SP_FLAG_PFS       = (1L << 2),
+  SILC_SKE_SP_FLAG_NONE      = 0x00,
+  SILC_SKE_SP_FLAG_NO_REPLY  = 0x01,
+  SILC_SKE_SP_FLAG_PFS       = 0x02,
+  SILC_SKE_SP_FLAG_MUTUAL    = 0x04,
 } SilcSKESecurityPropertyFlag;
 
 /* Security Properties negotiated between key exchange parties. This
@@ -106,8 +107,8 @@ struct SilcSKEStruct {
   /* Key Exchange payloads filled during key negotiation with
      remote data. Responder may save local data here as well. */
   SilcSKEStartPayload *start_payload;
-  SilcSKEOnePayload *ke1_payload;
-  SilcSKETwoPayload *ke2_payload;
+  SilcSKEKEPayload *ke1_payload;
+  SilcSKEKEPayload *ke2_payload;
 
   /* Temporary copy of the KE Start Payload used in the
      HASH computation. */
@@ -155,10 +156,11 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
                                         void *context);
 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
                                         SilcPublicKey public_key,
+                                        SilcPrivateKey private_key,
                                         SilcSKESendPacketCb send_packet,
                                         void *context);
 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
-                                       SilcBuffer ke2_payload,
+                                       SilcBuffer ke_payload,
                                        SilcSKEVerifyCb verify_key,
                                        void *verify_context,
                                        SilcSKECb callback,
@@ -167,6 +169,7 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
                                       SilcSocketConnection sock,
                                       char *version,
                                       SilcBuffer start_payload,
+                                      int mutual_auth,
                                       SilcSKECb callback,
                                       void *context);
 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
@@ -174,7 +177,9 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
                                         SilcSKESendPacketCb send_packet,
                                         void *context);
 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
-                                        SilcBuffer ke1_payload,
+                                        SilcBuffer ke_payload,
+                                        SilcSKEVerifyCb verify_key,
+                                        void *verify_context,
                                         SilcSKECb callback,
                                         void *context);
 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
@@ -204,7 +209,8 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
                                  SilcInt *rnd);
 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
                                 unsigned char *return_hash,
-                                unsigned int *return_hash_len);
+                                unsigned int *return_hash_len,
+                                int initiator);
 SilcSKEStatus 
 silc_ske_process_key_material_data(unsigned char *data,
                                   unsigned int data_len,