updates.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 27 Mar 2001 11:08:03 +0000 (11:08 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 27 Mar 2001 11:08:03 +0000 (11:08 +0000)
15 files changed:
TODO
apps/silc/client_ops.c
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/server.c
doc/draft-riikonen-silc-pp-01.nroff
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_notify.c
lib/silcclient/command.c

diff --git a/TODO b/TODO
index 2b68195cb50f63b0465f386f3466f6d6e5dfb9ee..b8b30a67346d72ae6840037285f02709db86af5c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -74,9 +74,6 @@ TODO In SILC Server
  o TODO in commands (command.c and command_reply.c):
 
        o RESTART is not implemented
-       o CMODE should be rewritten as it uses a lot duplicated code.
-         Some of the modes may still not be implemented or is implemented
-         the wrong way.
        o In servers all command reply funtions should still call the
          pending command reply even if the reply was error.  In client
          it is not called but in server, I think, it must be called.
index b97484524ad96fa1e3d1c45769fdb7f0d43f0ee7..c6134960451cb19ad2f91b927229cde1577985e9 100644 (file)
@@ -183,10 +183,15 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
     client_entry = va_arg(vp, SilcClientEntry);
-    tmp = silc_client_chmode(va_arg(vp, unsigned int));
+    tmp_int = va_arg(vp, unsigned int);
+    (void)va_arg(vp, char *);
+    (void)va_arg(vp, char *);
     channel_entry = va_arg(vp, SilcChannelEntry);
+    
+    tmp = silc_client_chmode(tmp_int, channel_entry);
+    
     if (tmp)
-      snprintf(message, sizeof(message), "%s changed channel mode to +%s", 
+      snprintf(message, sizeof(message), "%s changed channel mode to +%s",
               client_entry->nickname, tmp);
     else
       snprintf(message, sizeof(message), "%s removed all channel modes", 
@@ -596,7 +601,8 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn,
          client->ops->say(client, conn, "Topic for %s: %s", 
                           app->screen->bottom_line->channel, topic);
        
-       app->screen->bottom_line->channel_mode = silc_client_chmode(mode);
+       app->screen->bottom_line->channel_mode = 
+         silc_client_chmode(mode, channel);
        silc_screen_print_bottom_line(app->screen, 0);
 
        /* Resolve the client information */
index 4dd4aeb3fc9fe453e7da285c905da14620a413eb..ed29b05e21e2befd1c879f0a2e3f23321d807514 100644 (file)
@@ -3311,6 +3311,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   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 short ident = silc_command_get_ident(cmd->payload);
 
@@ -3392,45 +3393,24 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
     /* Channel uses private keys to protect traffic. Client(s) has set the
        key locally they want to use, server does not know that key. */
-    /* Nothing interesting to do here now */
+    /* Nothing interesting to do here */
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
       /* The mode is removed and we need to generate and distribute
         new channel key. Clients are not using private channel keys
         anymore after this. */
 
-      /* XXX Duplicated code, make own function for this!! LEAVE uses this
-        as well */
-
       /* Re-generate channel key */
       silc_server_create_channel_key(server, channel, 0);
       
-      /* Encode channel key payload to be distributed on the channel */
-      packet = 
-       silc_channel_key_payload_encode(tmp_len2, tmp_id,
-                                       strlen(channel->channel_key->
-                                              cipher->name),
-                                       channel->channel_key->cipher->name,
-                                       channel->key_len / 8, channel->key);
-      
-      /* If we are normal server then we will send it to our router.  If we
-        are router we will send it to all local servers that has clients on
-        the channel */
-      if (server->server_type == SILC_SERVER) {
-       if (!server->standalone)
-         silc_server_packet_send(server, 
-                                 cmd->server->router->connection,
-                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
-                                 packet->len, TRUE);
-      } else {
-       
-      }
-      
-      /* Send to locally connected clients on the channel */
-      silc_server_packet_send_local_channel(server, channel, 
-                                           SILC_PACKET_CHANNEL_KEY, 0,
-                                           packet->data, packet->len, FALSE);
-      silc_buffer_free(packet);
+      /* Send the channel key. This sends it to our local clients and if
+        we are normal server to our router as well. */
+      silc_server_send_channel_key(server, NULL, channel, 
+                                  server->server_type == SILC_ROUTER ? 
+                                  FALSE : !server->standalone);
+
+      cipher = channel->channel_key->cipher->name;
+      hmac = channel->hmac->hmac->name;
     }
   }
   
@@ -3484,70 +3464,42 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
       /* Cipher to use protect the traffic */
-      unsigned int key_len;
 
       /* Get cipher */
-      tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
-      if (!tmp) {
+      cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
+      if (!cipher) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
       }
 
-      /* XXX Duplicated code, make own function for this!! */
-    
       /* Delete old cipher and allocate the new one */
       silc_cipher_free(channel->channel_key);
-      if (!silc_cipher_alloc(tmp, &channel->channel_key)) {
+      if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
-      key_len = silc_cipher_get_key_len(channel->channel_key) / 8;
 
       /* Re-generate channel key */
-      silc_server_create_channel_key(server, channel, key_len);
-    
-      /* Encode channel key payload to be distributed on the channel */
-      packet = 
-       silc_channel_key_payload_encode(tmp_len2, tmp_id,
-                                       strlen(channel->channel_key->
-                                              cipher->name),
-                                       channel->channel_key->cipher->name,
-                                       channel->key_len / 8, channel->key);
-    
-      /* If we are normal server then we will send it to our router.  If we
-        are router we will send it to all local servers that has clients on
-        the channel */
-      if (server->server_type == SILC_SERVER) {
-       if (!server->standalone)
-         silc_server_packet_send(server, 
-                                 cmd->server->router->connection,
-                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
-                                 packet->len, TRUE);
-      } else {
-       
-      }
+      silc_server_create_channel_key(server, channel, 0);
     
-      /* Send to locally connected clients on the channel */
-      silc_server_packet_send_local_channel(server, channel, 
-                                           SILC_PACKET_CHANNEL_KEY, 0,
-                                         packet->data, packet->len, FALSE);
-      silc_buffer_free(packet);
+      /* Send the channel key. This sends it to our local clients and if
+        we are normal server to our router as well. */
+      silc_server_send_channel_key(server, NULL, channel, 
+                                  server->server_type == SILC_ROUTER ? 
+                                  FALSE : !server->standalone);
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       /* Cipher mode is unset. Remove the cipher and revert back to 
         default cipher */
-      char *cipher = channel->channel_key->cipher->name;
-
-      /* Generate new cipher and key for the channel */
-
-      /* XXX Duplicated code, make own function for this!! */
+      cipher = channel->cipher;
 
       /* Delete old cipher and allocate default one */
       silc_cipher_free(channel->channel_key);
-      if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+      if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc", 
+                            &channel->channel_key)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                   SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
@@ -3556,32 +3508,66 @@ SILC_SERVER_CMD_FUNC(cmode)
       /* Re-generate channel key */
       silc_server_create_channel_key(server, channel, 0);
       
-      /* Encode channel key payload to be distributed on the channel */
-      packet = 
-       silc_channel_key_payload_encode(tmp_len2, tmp_id,
-                                       strlen(channel->channel_key->
-                                              cipher->name),
-                                       channel->channel_key->cipher->name,
-                                       channel->key_len / 8, channel->key);
-      
-      /* If we are normal server then we will send it to our router.  If we
-        are router we will send it to all local servers that has clients on
-        the channel */
-      if (server->server_type == SILC_SERVER) {
-       if (!server->standalone)
-         silc_server_packet_send(server, 
-                                 cmd->server->router->connection,
-                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
-                                 packet->len, TRUE);
-      } else {
-       
+      /* Send the channel key. This sends it to our local clients and if
+        we are normal server to our router as well. */
+      silc_server_send_channel_key(server, NULL, channel, 
+                                  server->server_type == SILC_ROUTER ? 
+                                  FALSE : !server->standalone);
+    }
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_HMAC) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
+      /* HMAC to use protect the traffic */
+      unsigned char hash[32];
+
+      /* Get hmac */
+      hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
+      if (!hmac) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                  SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
       }
-      
-      /* Send to locally connected clients on the channel */
-      silc_server_packet_send_local_channel(server, channel, 
-                                           SILC_PACKET_CHANNEL_KEY, 0,
-                                           packet->data, packet->len, FALSE);
-      silc_buffer_free(packet);
+
+      /* Delete old hmac and allocate the new one */
+      silc_hmac_free(channel->hmac);
+      if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+       goto out;
+      }
+
+      /* Set the HMAC key out of current channel key. The client must do
+        this locally. */
+      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+                    hash);
+      silc_hmac_set_key(channel->hmac, hash, 
+                       silc_hash_len(channel->hmac->hash));
+      memset(hash, 0, sizeof(hash));
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
+      /* Hmac mode is unset. Remove the hmac and revert back to 
+        default hmac */
+      unsigned char hash[32];
+      hmac = channel->hmac_name;
+
+      /* Delete old hmac and allocate default one */
+      silc_hmac_free(channel->hmac);
+      if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL, 
+                          &channel->hmac)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+       goto out;
+      }
+
+      /* Set the HMAC key out of current channel key. The client must do
+        this locally. */
+      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+                    hash);
+      silc_hmac_set_key(channel->hmac, hash, 
+                       silc_hash_len(channel->hmac->hash));
+      memset(hash, 0, sizeof(hash));
     }
   }
 
@@ -3591,16 +3577,19 @@ SILC_SERVER_CMD_FUNC(cmode)
   /* Send CMODE_CHANGE notify */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
                                     cidp->data, cidp->len, 
-                                    tmp_mask, tmp_len);
+                                    tmp_mask, tmp_len,
+                                    cipher, cipher ? strlen(cipher) : 0,
+                                    hmac, hmac ? strlen(hmac) : 0);
 
   /* Set CMODE notify type to network */
   if (!server->standalone)
     silc_server_send_notify_cmode(server, server->router->connection,
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
-                                 mode_mask, client->id, SILC_ID_CLIENT_LEN);
+                                 mode_mask, client->id, SILC_ID_CLIENT_LEN,
+                                 cipher, hmac);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
index 4b865ad8d0375c22370677f801939b206a06fcfa..fe25519c9ea2644d9be804e0227ebab621807b05 100644 (file)
@@ -722,6 +722,11 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     silc_free(id);
   }
 
+  if (entry->hmac_name && hmac) {
+    silc_free(entry->hmac_name);
+    entry->hmac_name = strdup(hmac->hmac->name);
+  }
+
   /* Get the ban list */
   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
   if (tmp) {
index 888f5bc2168879bc8ac8ad534a2c03635f59a93c..a15acc164a29ac1b864e110264377a47f9b13fea 100644 (file)
@@ -629,6 +629,10 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
       memset(entry->key, 0, entry->key_len / 8);
       silc_free(entry->key);
     }
+    if (entry->cipher)
+      silc_free(entry->cipher);
+    if (entry->hmac_name)
+      silc_free(entry->hmac_name);
 
     /* Free all data, free also any reference from the client's channel
        list since they share the same memory. */
index 637564849bf9aca36d74f0ab24a1d49425665e15..ae2757d31b1b32b1a4331ec3d57d4e3f026e4c97 100644 (file)
@@ -356,6 +356,11 @@ struct SilcClientEntryStruct {
        Default cipher of the channel. If this is NULL then server picks
        the cipher to be used. This can be set at SILC_COMMAND_JOIN.
 
+   char *hmac_name
+
+       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.
+
    SilcServerEntry router
 
        This is a pointer to the server list. This is the router server 
@@ -388,6 +393,7 @@ struct SilcChannelEntryStruct {
   int global_users;
   char *topic;
   char *cipher;
+  char *hmac_name;
 
   unsigned int user_limit;
   unsigned char *passphrase;
index ecfab1cf72e8412f090f132571f697177dbb0d05..d261e514f10d57022590133d52bda40ff9f618b2 100644 (file)
@@ -425,6 +425,26 @@ void silc_server_notify(SilcServer server,
     /* Change mode */
     channel->mode = mode;
     silc_free(channel_id);
+
+    /* Get the hmac */
+    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+    if (tmp) {
+      unsigned char hash[32];
+
+      if (channel->hmac)
+       silc_hmac_free(channel->hmac);
+      if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
+       goto out;
+
+      /* Set the HMAC key out of current channel key. The client must do
+        this locally. */
+      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+                    hash);
+      silc_hmac_set_key(channel->hmac, hash, 
+                       silc_hash_len(channel->hmac->hash));
+      memset(hash, 0, sizeof(hash));
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
index 4b271c4d9cc5c94e84b04063c3352e3c18cfa342..714479ea6a5f6ff9291d31ffeb26e54def37bd5a 100644 (file)
@@ -947,7 +947,8 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcChannelEntry channel,
                                   unsigned int mode_mask,
                                   SilcClientID *client_id,
-                                  unsigned int client_id_len)
+                                  unsigned int client_id_len,
+                                  char *cipher, char *hmac)
 {
   SilcBuffer idp;
   unsigned char mode[4];
@@ -957,8 +958,10 @@ void silc_server_send_notify_cmode(SilcServer server,
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              2, idp->data, idp->len,
-                              mode, 4);
+                              4, idp->data, idp->len,
+                              mode, 4,
+                              cipher, cipher ? strlen(cipher) : 0,
+                              hmac, hmac ? strlen(hmac) : 0);
   silc_buffer_free(idp);
 }
 
index cef2bbe4298138b804756f8b8d8a28e55e45ba26..89f3d61563d029d9b4ba22a8cdee8f14a31f08de 100644 (file)
@@ -127,7 +127,8 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcChannelEntry channel,
                                   unsigned int mode_mask,
                                   SilcClientID *client_id,
-                                  unsigned int client_id_len);
+                                  unsigned int client_id_len,
+                                  char *cipher, char *hmac);
 void silc_server_send_notify_cumode(SilcServer server,
                                    SilcSocketConnection sock,
                                    int broadcast,
index df6a94db45eb4bf98f9a345bd042518dab4e1aea..a6ae79ff22a1dc677976eb4d994219a62ab66f1d 100644 (file)
@@ -2477,6 +2477,9 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
     return NULL;
   }
 
+  entry->cipher = strdup(cipher);
+  entry->hmac_name = strdup(hmac);
+
   /* Now create the actual key material */
   silc_server_create_channel_key(server, entry, 
                                 silc_cipher_get_key_len(key) / 8);
@@ -2670,6 +2673,10 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     goto out;
   }
 
+  if (channel->cipher)
+    silc_free(channel->cipher);
+  channel->cipher = strdup(cipher);
+
   /* Save the key */
   channel->key_len = tmp_len * 8;
   channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
index 8ab11cf1f61516f66b9b7fadd3f61626f15d7bee..8dddf602ffee2f3182f3675f751584a2501951fb 100644 (file)
@@ -1229,11 +1229,16 @@ ID's sent in arguments are sent inside ID Payload.
       Sent when channel mode has changed.  This type must be sent only to
       the clients who is joined on the channel whose mode was changed.
 
-      Max Arguments:  2
+      Max Arguments:  4
           Arguments:  (1) <Client ID>  (2) <mode mask>
+                      (3) [<cipher>]   (4) <[hmac>]     
 
       The <Client ID> is the client who changed the mode.  The <mode mask>
-      is the new mode mask of the channel.
+      is the new mode mask of the channel.  The client can safely ignore
+      the <cipher> argument since the SILC_PACKET_CHANNEL_KEY packet will
+      force the new channel key change anyway.  The <hmac> argument is
+      important since the client is responsible of setting the new HMAC
+      and the hmac key into use.
 
 
 8     SILC_NOTIFY_TYPE_CUMODE_CHANGE
index 4ea2a2d8e34d62c349b285bbfb8cfee777f6008a..300789bfa14fdb4c902742799363700c95c3d278 100644 (file)
@@ -1285,17 +1285,17 @@ char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
     strncat(string, "a", 1);
 
   if (mode & SILC_CHANNEL_MODE_CIPHER) {
-    char cipher[50];
+    char cipher[30];
     memset(cipher, 0, sizeof(cipher));
-    snprintf(cipher, sizeof(cipher), "c (%s)", 
+    snprintf(cipher, sizeof(cipher), " c (%s)", 
             channel->channel_key->cipher->name);
     strncat(string, cipher, strlen(cipher));
   }
 
   if (mode & SILC_CHANNEL_MODE_HMAC) {
-    char hmac[50];
+    char hmac[30];
     memset(hmac, 0, sizeof(hmac));
-    snprintf(hmac, sizeof(hmac), "h (%s)", 
+    snprintf(hmac, sizeof(hmac), " h (%s)", 
             channel->hmac->hmac->name);
     strncat(string, hmac, strlen(hmac));
   }
index f7c6e3314b34294e0d87ba6c2356d67222f73fa0..e0ff8e767e118f43c0b0773cdccde019e512d61f 100644 (file)
@@ -247,7 +247,7 @@ void silc_client_replace_from_channels(SilcClient client,
                                       SilcClientConnection conn,
                                       SilcClientEntry old,
                                       SilcClientEntry new);
-char *silc_client_chmode(unsigned int mode);
+char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel);
 char *silc_client_chumode(unsigned int mode);
 char *silc_client_chumode_char(unsigned int mode);
 void silc_client_process_failure(SilcClient client,
index bccd100986430c01d5f4aec8b497cbd96746e62c..0aa343ee5680cf1f5afa481cdb4b0d07736d6dce 100644 (file)
@@ -454,10 +454,28 @@ void silc_client_notify_by_server(SilcClient client,
     /* Save the new mode */
     channel->mode = mode;
 
+    /* Get the hmac */
+    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+    if (tmp) {
+      unsigned char hash[32];
+
+      if (channel->hmac)
+       silc_hmac_free(channel->hmac);
+      if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
+       goto out;
+
+      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
+                    hash);
+      silc_hmac_set_key(channel->hmac, hash, 
+                       silc_hash_len(channel->hmac->hash));
+      memset(hash, 0, sizeof(hash));
+    }
+
     /* Notify application. The channel entry is sent last as this notify
        is for channel but application don't know it from the arguments
        sent by server. */
-    client->ops->notify(client, conn, type, client_entry, mode, channel);
+    client->ops->notify(client, conn, type, client_entry, mode, NULL, 
+                       tmp, channel);
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
index cf3c0c4e7ab06262d03168ac9b773f17a03588e7..7a6f3ea92259ac2f622a1f295c3d1f58216459ca 100644 (file)
@@ -1217,13 +1217,23 @@ SILC_CLIENT_CMD_FUNC(cmode)
     case 'c':
       if (add) {
        mode |= SILC_CHANNEL_MODE_CIPHER;
-       type = 8;
+       type = 5;
        arg = cmd->argv[3];
        arg_len = cmd->argv_lens[3];
       } else {
        mode &= ~SILC_CHANNEL_MODE_CIPHER;
       }
       break;
+    case 'h':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_HMAC;
+       type = 6;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_HMAC;
+      }
+      break;
     default:
       COMMAND_ERROR;
       goto out;