Added support for the new PKCS API, Auth API and other API
authorPekka Riikonen <priikone@silcnet.org>
Tue, 10 Jul 2007 17:21:13 +0000 (17:21 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 10 Jul 2007 17:21:13 +0000 (17:21 +0000)
changes.

20 files changed:
CHANGES.RUNTIME
TODO
apps/irssi/CHANGES [new file with mode: 0644]
apps/irssi/src/perl/silc/Makefile.PL.in
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-channels.c
apps/irssi/src/silc/core/silc-core.c
apps/irssi/src/silc/core/silc-queries.c
apps/irssi/src/silc/core/silc-servers.c
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_attrs.c
lib/silcclient/client_channel.c
lib/silcclient/client_entry.c
lib/silcclient/client_internal.h
lib/silcclient/client_prvmsg.c
lib/silcclient/client_register.c
lib/silcclient/client_register.h
lib/silcclient/command.c
lib/silcclient/silcclient.h

index e8410c936deb4ff326e973c4a9aa31de664cfacb..a2c6bdb920b7b7f0279c5cef80fbd13feeafa6b9 100644 (file)
@@ -1,3 +1,12 @@
+Tue Jul 10 20:02:04 EEST 2007  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added queue entry free list to thread pool instead of
+         allocating new entry everytime new entry is needed.  Affected
+         file is lib/silcutil/silcthread.c.
+
+       * Added support for new PKCS API and other API changes to
+         client library.  Affected files are in lib/silcclient/.
+
 Mon Jul  9 20:21:13 EEST 2007  Pekka Riikonen <priikone@silcnet.org>
 
        * Added SILC Accelerator Library.  Provides generic way to
diff --git a/TODO b/TODO
index dac3d03fd81c1fca59dd8cb80d012ef9ec4b4486..f32a223417ad946f64ea7a5c6e28868a88600148 100644 (file)
--- a/TODO
+++ b/TODO
@@ -351,13 +351,22 @@ SILC Accelerator Library
 lib/silcmath
 ============
 
- o Import TFM.  Talk to Tom to add the missing functions.  Use TFM in
-   client and client library, but TMA in server, due to the significantly
-   increased memory consumption with TFM, and the rare need for public
-   key operations in server.
-
-   We want TFM's speed but not TFM's memory requirements.  Talk to Tom
-   about making the TFM mp dynamic just as it is in LTM.
+ o Import TFM.  We want TFM's speed but its memory requirements are
+   just too much.  By default it uses large pre-allocated tables which 
+   will eat memory when there are thousands of public keys in system.
+   We probably want to change TFM's fp_int dynamic so that a specific
+   size can be allocated for the int.  We could have two new functions:
+
+   SilcBool silc_mp_init_size(SilcMPInt *mp, SilcUInt32 bit_size);
+   SilcBool silc_mp_sinit_size(SilcStack stack, SilcMPInt *mp,
+                              SilcUInt32 bit_size);
+
+   Which by default allocates `bit_size' bits instead of some default
+   value.  silc_mp_init would allocate the default FP_SIZE with TFM
+   and do normal init with TMA and GMP.  _init_size with TMA and GMP
+   would be same as _init.
+
+ o Add AND, OR and XOR support to TFM or ask Tom to do it.
 
  o The SILC MP API function must start returning indication of success
    and failure of the operation.
diff --git a/apps/irssi/CHANGES b/apps/irssi/CHANGES
new file mode 100644 (file)
index 0000000..5949f02
--- /dev/null
@@ -0,0 +1,7 @@
+Tue Jul 10 20:13:47 EEST 2007  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added support for the new PKCS API.
+
+-----------------------------------------------------------------------------
+
+For older changes please see the CHANGES file from the CVS tree.
index 9c1b07716d3ae1972483954468c65e4152cab83e..833cf402b44ef53afd2c8af893d0342384de8562 100644 (file)
@@ -8,5 +8,5 @@ WriteMakefile('NAME' => 'Irssi::Silc',
              'LIBS' => '',
              'OBJECT' => '$(O_FILES)',
              'TYPEMAPS' => ['../common/typemap'],
-             'INC' => '-I../../.. -I@top_srcdir@/src -I@top_srcdir@/src/core -I@top_srcdir@/src/silc/core -I@top_srcdir@/src/silc -I$(silc_top_srcdir) -I$(silc_top_srcdir)/lib/silccore -I$(silc_top_srcdir)/lib/silccrypt -I$(silc_top_srcdir)/lib/silcmath -DHAVE_SILCDEFS_H -I$(silc_top_srcdir)/lib/silcske -I$(silc_top_srcdir)/lib/silcsim -I$(silc_top_srcdir)/lib/silcskr -I$(silc_top_srcdir)/lib/silchttp -I$(silc_top_srcdir)/lib/silcasn1 -I$(silc_top_srcdir)/lib/silcapputil -I$(silc_top_srcdir)/lib/silcvcard -I$(silc_top_srcdir)/lib/silcutil -I$(silc_top_srcdir)/lib/silcsftp -I$(silc_top_srcdir)/lib/silcclient -I$(silc_top_srcdir)/lib/contrib -I$(silc_top_srcdir)/includes -I$(silc_top_srcdir)/doc @GLIB_CFLAGS@',
+             'INC' => '-I../../.. -I@top_srcdir@/src -I@top_srcdir@/src/core -I@top_srcdir@/src/silc/core -I@top_srcdir@/src/silc -I$(silc_top_srcdir) -I$(silc_top_srcdir)/lib/silccore -I$(silc_top_srcdir)/lib/silccrypt -I$(silc_top_srcdir)/lib/silcmath -DHAVE_SILCDEFS_H -I$(silc_top_srcdir)/lib/silcske -I$(silc_top_srcdir)/lib/silcsim -I$(silc_top_srcdir)/lib/silcskr -I$(silc_top_srcdir)/lib/silchttp -I$(silc_top_srcdir)/lib/silcasn1 -I$(silc_top_srcdir)/lib/silcapputil -I$(silc_top_srcdir)/lib/silcvcard -I$(silc_top_srcdir)/lib/silcutil -I$(silc_top_srcdir)/lib/silcsftp -I$(silc_top_srcdir)/lib/silcclient -I$(silc_top_srcdir)/lib/silcacc -I$(silc_top_srcdir)/lib/contrib -I$(silc_top_srcdir)/includes -I$(silc_top_srcdir)/doc @GLIB_CFLAGS@',
              'VERSION_FROM' => '@srcdir@/Silc.pm');
index 38e90d0844553855d9cc38cc2497756754e37975..25afdb040150321991474180add62f4e30ef6d08 100644 (file)
@@ -185,7 +185,7 @@ static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
     if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
       continue;
 
-    pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
+    pk = silc_pkcs_public_key_encode(NULL, pubkey, &pk_len);
     if (!pk)
       continue;
 
@@ -236,6 +236,12 @@ void silc_say_error(char *msg, ...)
   va_end(va);
 }
 
+void static verify_message_signature_verified(SilcBool success,
+                                             void *context)
+{
+  *(SilcBool *)context = success;
+}
+
 /* Try to verify a message using locally stored public key data */
 
 int verify_message_signature(SilcClientEntry sender,
@@ -248,6 +254,7 @@ int verify_message_signature(SilcClientEntry sender,
   SilcUInt32 pk_datalen;
   struct stat st;
   int ret = SILC_MSG_SIGNED_VERIFIED, i;
+  SilcBool verified = FALSE;
 
   /* get public key from the signature payload and compare it with the
      one stored in the client entry */
@@ -309,9 +316,12 @@ int verify_message_signature(SilcClientEntry sender,
   }
 
   /* the public key is now in pk, our "level of trust" in ret */
-  if ((pk) && silc_message_signed_verify(message, pk,
-                                        sha1hash) != SILC_AUTH_OK)
-    ret = SILC_MSG_SIGNED_FAILED;
+  if (pk) {
+    silc_message_signed_verify(message, pk, sha1hash,
+                              verify_message_signature_verified, &verified);
+    if (!verified)
+      ret = SILC_MSG_SIGNED_FAILED;
+  }
 
   if (pk)
     silc_pkcs_public_key_free(pk);
@@ -2433,7 +2443,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   }
 
   /* Encode public key */
-  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  pk = silc_pkcs_public_key_encode(NULL, public_key, &pk_len);
   if (!pk) {
     if (completion)
       completion(FALSE, context);
@@ -2574,7 +2584,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     }
 
     /* Encode the key data */
-    encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
+    encpk = silc_pkcs_public_key_encode(NULL, local_pubkey, &encpk_len);
     if (!encpk) {
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
index 1c6bb8d979a47376e49d0825e37da818a0292e45..8917fc2ced40b8d36966c5754ad0893b89600d3a 100644 (file)
@@ -1092,7 +1092,7 @@ void silc_list_key(const char *pub_filename, int verbose)
   silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
   ident = &silc_pubkey->identifier;
 
-  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  pk = silc_pkcs_public_key_encode(NULL, public_key, &pk_len);
   if (!pk)
     return;
   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
index 8b6f9f74ed50fc08326068ad805b09a3c27d86d0..8253713d99296961144c5f3f49c68ade0519f3a8 100644 (file)
@@ -302,9 +302,6 @@ static void silc_register_cipher(SilcClient client, const char *cipher)
 #endif
     }
   }
-
-  /* Register other defaults */
-  silc_cipher_register_default();
 }
 
 static void silc_register_hash(SilcClient client, const char *hash)
@@ -328,9 +325,6 @@ static void silc_register_hash(SilcClient client, const char *hash)
 #endif
     }
   }
-
-  /* Register other defaults */
-  silc_hash_register_default();
 }
 
 static void silc_register_hmac(SilcClient client, const char *hmac)
@@ -354,9 +348,6 @@ static void silc_register_hmac(SilcClient client, const char *hmac)
 #endif
     }
   }
-
-  /* Register other defaults */
-  silc_hmac_register_default();
 }
 
 /* Finalize init. Init finish signal calls this. */
@@ -408,7 +399,6 @@ void silc_opt_callback(poptContext con,
   if ((argc == 2) && (strcasecmp(argv[1], "list-ciphers") == 0)) {
 #else
   if (strcmp(opt->longName, "list-ciphers") == 0) {
-    silc_cipher_register_default();
 #endif
     silc_client_list_ciphers();
     FUNCTION_EXIT;
@@ -418,7 +408,6 @@ void silc_opt_callback(poptContext con,
   if ((argc == 2) && (strcasecmp(argv[1], "list-hash-funcs") == 0)) {
 #else
   if (strcmp(opt->longName, "list-hash-funcs") == 0) {
-    silc_hash_register_default();
 #endif
     silc_client_list_hash_funcs();
     FUNCTION_EXIT;
@@ -428,7 +417,6 @@ void silc_opt_callback(poptContext con,
   if ((argc == 2) && (strcasecmp(argv[1], "list-hmacs") == 0)) {
 #else
   if (strcmp(opt->longName, "list-hmacs") == 0) {
-    silc_hmac_register_default();
 #endif
     silc_client_list_hmacs();
     FUNCTION_EXIT;
@@ -438,7 +426,6 @@ void silc_opt_callback(poptContext con,
   if ((argc == 2) && (strcasecmp(argv[1], "list-pkcs") == 0)) {
 #else
   if (strcmp(opt->longName, "list-pkcs") == 0) {
-    silc_pkcs_register_default();
 #endif
     silc_client_list_pkcs();
     FUNCTION_EXIT;
@@ -534,10 +521,7 @@ void silc_opt_callback(poptContext con,
                       MSGLEVEL_CRAP, SILCTXT_CONFIG_NEXTTIME);
     goto out;
 #else
-    silc_cipher_register_default();
-    silc_pkcs_register_default();
-    silc_hash_register_default();
-    silc_hmac_register_default();
+    silc_crypto_init(NULL);
     silc_create_key_pair(opt_pkcs, opt_bits, NULL, NULL,
                         NULL, NULL, NULL, NULL, TRUE);
     exit(0);
@@ -562,10 +546,7 @@ void silc_opt_callback(poptContext con,
                            ENTRY_REDIRECT_FLAG_HIDDEN, rec);
     goto out;
 #else
-    silc_cipher_register_default();
-    silc_pkcs_register_default();
-    silc_hash_register_default();
-    silc_hmac_register_default();
+    silc_crypto_init(NULL);
     silc_change_private_key_passphrase(arg, NULL, NULL);
     exit(0);
 #endif
@@ -574,10 +555,7 @@ void silc_opt_callback(poptContext con,
 #ifndef SILC_PLUGIN
   if (strcmp(opt->longName, "show-key") == 0) {
     /* Dump the key */
-    silc_cipher_register_default();
-    silc_pkcs_register_default();
-    silc_hash_register_default();
-    silc_hmac_register_default();
+    silc_crypto_init(NULL);
     silc_show_public_key_file((char *)arg);
     exit(0);
   }
@@ -794,7 +772,6 @@ void silc_core_init(void)
   if (init_failed)
     return;
 #endif
-  silc_pkcs_register_default();
 
 #ifdef SILC_PLUGIN
   command_bind("silc", MODULE_NAME, (SIGNAL_FUNC) silc_opt_callback);
index 271e3d5e77b41d44ad8e18df7ab5cc68198a15f2..664eece66117fdb6cffb98d86b102a625c533fe8 100644 (file)
@@ -560,6 +560,11 @@ typedef struct {
   bool nopk;
 } *AttrVerify;
 
+static void silc_query_attributes_verify(SilcBool success, void *context)
+{
+  *(SilcBool *)context = success;
+}
+
 void silc_query_attributes_print(SILC_SERVER_REC *server,
                                 SilcClient client,
                                 SilcClientConnection conn,
@@ -842,14 +847,16 @@ void silc_query_attributes_print(SILC_SERVER_REC *server,
     /* Verify the signature now */
     unsigned char *verifyd;
     SilcUInt32 verify_len;
+    SilcBool verified = FALSE;
 
     if (verify->public_key) {
       verifyd = silc_attribute_get_verify_data(attrs, FALSE, &verify_len);
-      if (verifyd && silc_pkcs_verify(verify->public_key,
-                                     usersign.data,
-                                     usersign.data_len,
-                                     verifyd, verify_len,
-                                     sha1hash)) {
+      if (verifyd)
+       silc_pkcs_verify(verify->public_key, usersign.data,
+                        usersign.data_len, verifyd, verify_len, sha1hash,
+                        silc_query_attributes_verify, &verified);
+
+      if (verified) {
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_VERIFIED);
       } else {
@@ -873,6 +880,7 @@ void silc_query_attributes_print(SILC_SERVER_REC *server,
     SilcPKCSType type = 0;
     unsigned char *verifyd;
     SilcUInt32 verify_len;
+    SilcBool verified = FALSE;
 
     if (!strcmp(serverpk.type, "silc-rsa"))
       type = SILC_PKCS_SILC;
@@ -887,11 +895,11 @@ void silc_query_attributes_print(SILC_SERVER_REC *server,
                                   serverpk.data_len,
                                   &public_key)) {
       verifyd = silc_attribute_get_verify_data(attrs, TRUE, &verify_len);
-      if (verifyd && silc_pkcs_verify(public_key,
-                                     serversign.data,
-                                     serversign.data_len,
-                                     verifyd, verify_len,
-                                     sha1hash)) {
+      if (verifyd)
+       silc_pkcs_verify(public_key, serversign.data,
+                        serversign.data_len, verifyd, verify_len, sha1hash,
+                        silc_query_attributes_verify, &verified);
+      if (verified) {
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_VERIFIED);
       } else {
index e16fb02cdc056fef1116a982f49259c3bf0d7483..bfd5f600e5e67012156f3990fa1c21d6edb0f41a 100644 (file)
@@ -418,7 +418,7 @@ static void sig_connected_stream_created(SilcSocketStreamStatus status,
 
   /* Try to read detached session data and use it if found. */
   file = silc_get_session_filename(server);
-  params.detach_data = silc_file_readfile(file, &params.detach_data_len);
+  params.detach_data = silc_file_readfile(file, &params.detach_data_len, NULL);
   if (params.detach_data)
     params.detach_data[params.detach_data_len] = 0;
   if (params.detach_data)
index 9fef6df8b6ed453bd9a1353bbc31d529be815925..6a634b4f92c4464aa00ab716b3c3122676d3d1a0 100644 (file)
@@ -952,12 +952,8 @@ void silc_client_free(SilcClient client)
   if (client->rng)
     silc_rng_free(client->rng);
 
-  if (!client->internal->params->dont_register_crypto_library) {
-    silc_cipher_unregister_all();
-    silc_pkcs_unregister_all();
-    silc_hash_unregister_all();
-    silc_hmac_unregister_all();
-  }
+  if (!client->internal->params->dont_register_crypto_library)
+    silc_crypto_uninit();
 
   silc_packet_engine_stop(client->internal->packet_engine);
   silc_dlist_uninit(client->internal->ftp_sessions);
@@ -1023,15 +1019,10 @@ SilcBool silc_client_init(SilcClient client, const char *username,
   if (!client->internal->ftp_sessions)
     return FALSE;
 
-  if (!client->internal->params->dont_register_crypto_library) {
+  if (!client->internal->params->dont_register_crypto_library)
     /* Initialize the crypto library.  If application has done this already
-       this has no effect.  Also, we will not be overriding something
-       application might have registered earlier. */
-    silc_cipher_register_default();
-    silc_pkcs_register_default();
-    silc_hash_register_default();
-    silc_hmac_register_default();
-  }
+       this has no effect. */
+    silc_crypto_init(NULL);
 
   /* Initialize random number generator */
   client->rng = silc_rng_alloc();
index ac1116d28289951ced21ef6933114ecb7f5cda68..e008e44fb3e8d7fd000946977d6ef142342b1d64 100644 (file)
@@ -60,7 +60,7 @@ typedef struct SilcClientEntryInternalStruct {
   unsigned int prv_resp    : 1; /* TRUE if we are responder when using
                                   private message keys. */
   SilcUInt16 resolve_cmd_ident;        /* Command identifier when resolving */
-  SilcAtomic8 refcnt;          /* Reference counter */
+  SilcAtomic16 refcnt;         /* Reference counter */
 } SilcClientEntryInternal;
 
 /* Internal channel entry context */
index 34902df05c31d6990d936ca328e564eb77245b1d..4831ed31daa4d5b946e9ccbaf8d82d5fc544e3a3 100644 (file)
 #include "silcclient.h"
 #include "client_internal.h"
 
+typedef struct {
+  SilcBuffer buffer;
+  SilcPKCSSignCb sign_cb;
+  void *context;
+} *SilcAttrSign;
+
 typedef struct {
   SilcBuffer buffer;
 } SilcAttrForeach;
@@ -72,19 +78,49 @@ static void silc_client_attributes_process_foreach(void *key, void *context,
                                                 data, data_len);
 }
 
+/* Attribute signature callback */
+
+static void
+silc_client_attributes_process_signed(SilcBool success,
+                                     const unsigned char *signature,
+                                     SilcUInt32 signature_len,
+                                     void *context)
+{
+  SilcAttrSign s = context;
+  SilcAttributeObjPk pk;
+
+  if (success) {
+    pk.type = NULL;
+    pk.data = (unsigned char *)signature;
+    pk.data_len = signature_len;
+    s->buffer =
+      silc_attribute_payload_encode(s->buffer,
+                                   SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE,
+                                   SILC_ATTRIBUTE_FLAG_VALID,
+                                   &pk, sizeof(pk));
+  }
+
+  s->sign_cb(TRUE, silc_buffer_data(s->buffer), silc_buffer_len(s->buffer),
+            s->context);
+
+  silc_buffer_free(s->buffer);
+  silc_free(s);
+}
+
 /* Process list of attributes.  Returns reply to the requested attributes. */
 
-SilcBuffer silc_client_attributes_process(SilcClient client,
-                                         SilcClientConnection conn,
-                                         SilcDList attrs)
+void silc_client_attributes_process(SilcClient client,
+                                   SilcClientConnection conn,
+                                   SilcDList attrs,
+                                   SilcPKCSSignCb sign_cb,
+                                   void *context)
 {
+  SilcAttrSign s;
   SilcBuffer buffer = NULL;
   SilcAttrForeach f;
   SilcAttribute attribute;
   SilcAttributePayload attr;
   SilcAttributeObjPk pk;
-  unsigned char sign[2048 + 1];
-  SilcUInt32 sign_len;
 
   SILC_LOG_DEBUG(("Process Requested Attributes"));
 
@@ -92,12 +128,13 @@ SilcBuffer silc_client_attributes_process(SilcClient client,
      attributes, ignore the request. */
   if (!conn->internal->attrs) {
     SILC_LOG_DEBUG(("User has not set any attributes"));
-    return NULL;
+    sign_cb(FALSE, NULL, 0, context);
+    return;
   }
 
   /* Always put our public key. */
   pk.type = "silc-rsa";
-  pk.data = silc_pkcs_public_key_encode(conn->public_key, &pk.data_len);
+  pk.data = silc_pkcs_public_key_encode(NULL, conn->public_key, &pk.data_len);
   buffer = silc_attribute_payload_encode(buffer,
                                         SILC_ATTRIBUTE_USER_PUBLIC_KEY,
                                         pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
@@ -123,21 +160,19 @@ SilcBuffer silc_client_attributes_process(SilcClient client,
   }
   buffer = f.buffer;
 
-  /* Finally compute the digital signature of all the data we provided. */
-  if (silc_pkcs_sign(conn->private_key, silc_buffer_data(buffer),
-                    silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
-                    TRUE, conn->internal->sha1hash)) {
-    pk.type = NULL;
-    pk.data = sign;
-    pk.data_len = sign_len;
-    buffer =
-      silc_attribute_payload_encode(buffer,
-                                   SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE,
-                                   SILC_ATTRIBUTE_FLAG_VALID,
-                                   &pk, sizeof(pk));
+  s = silc_calloc(1, sizeof(*s));
+  if (!s) {
+    sign_cb(FALSE, NULL, 0, context);
+    return;
   }
+  s->sign_cb = sign_cb;
+  s->context = context;
+  s->buffer = buffer;
 
-  return buffer;
+  /* Finally compute the digital signature of all the data we provided. */
+  silc_pkcs_sign(conn->private_key, silc_buffer_data(buffer),
+                silc_buffer_len(buffer), TRUE, conn->internal->sha1hash,
+                silc_client_attributes_process_signed, s);
 }
 
 static void silc_client_attribute_destruct(void *key, void *context,
index 1d78d221b6f6c438ddb6980ef335ae5cf59b17b7..4fcfb08c214c2667785f1767f8a372c045254f25 100644 (file)
 
 /************************** Channel Message Send ****************************/
 
+typedef struct {
+  SilcClient client;
+  SilcClientConnection conn;
+  SilcChannelEntry channel;
+} *SilcClientChannelMessageContext;
+
+/* Message payload encoding callback */
+
+static void silc_client_send_channel_message_final(SilcBuffer message,
+                                                  void *context)
+{
+  SilcClientChannelMessageContext c = context;
+
+  /* Send the channel message */
+  if (message)
+    silc_packet_send_ext(c->conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
+                        0, NULL, SILC_ID_CHANNEL, &c->channel->id,
+                        silc_buffer_datalen(message), NULL, NULL);
+
+  silc_client_unref_channel(c->client, c->conn, c->channel);
+  silc_free(c);
+}
+
 /* Sends channel message to `channel'. */
 
 SilcBool silc_client_send_channel_message(SilcClient client,
@@ -35,11 +58,10 @@ SilcBool silc_client_send_channel_message(SilcClient client,
                                          unsigned char *data,
                                          SilcUInt32 data_len)
 {
+  SilcClientChannelMessageContext c;
   SilcChannelUser chu;
-  SilcBuffer buffer;
   SilcCipher cipher;
   SilcHmac hmac;
-  SilcBool ret;
   SilcID sid, rid;
 
   SILC_LOG_DEBUG(("Sending channel message"));
@@ -109,27 +131,26 @@ SilcBool silc_client_send_channel_message(SilcClient client,
     return FALSE;
   }
 
-  /* Encode the message payload. This also encrypts the message payload. */
+  c = silc_calloc(1, sizeof(*c));
+  if (!c)
+    return FALSE;
+
+  c->client = client;
+  c->conn = conn;
+  c->channel = silc_client_ref_channel(client, conn, channel);
+
   sid.type = SILC_ID_CLIENT;
   sid.u.client_id = chu->client->id;
   rid.type = SILC_ID_CHANNEL;
   rid.u.channel_id = chu->channel->id;
-  buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
-                                      cipher, hmac, client->rng, NULL,
-                                      conn->private_key, hash, &sid, &rid,
-                                      NULL);
-  if (silc_unlikely(!buffer)) {
-    SILC_LOG_ERROR(("Error encoding channel message"));
-    return FALSE;
-  }
 
-  /* Send the channel message */
-  ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
-                            0, NULL, SILC_ID_CHANNEL, &channel->id,
-                            silc_buffer_datalen(buffer), NULL, NULL);
+  /* Encode the message payload. This also encrypts the message payload. */
+  silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
+                             cipher, hmac, client->rng, NULL,
+                             conn->private_key, hash, &sid, &rid, NULL,
+                             silc_client_send_channel_message_final, c);
 
-  silc_buffer_free(buffer);
-  return ret;
+  return TRUE;
 }
 
 /************************* Channel Message Receive **************************/
index 1f39eed2c921b5a0c6a94a0cdddb39299d0ce980..d3d6e44da3a6f88631e35bbae40db1cefa719990 100644 (file)
@@ -791,7 +791,7 @@ SilcClientEntry silc_client_add_client(SilcClient client,
     return NULL;
 
   silc_rwlock_alloc(&client_entry->internal.lock);
-  silc_atomic_init8(&client_entry->internal.refcnt, 0);
+  silc_atomic_init16(&client_entry->internal.refcnt, 0);
   client_entry->id = *id;
   client_entry->mode = mode;
   client_entry->realname = userinfo ? strdup(userinfo) : NULL;
@@ -995,7 +995,7 @@ void silc_client_del_client_entry(SilcClient client,
   silc_client_ftp_session_free_client(client, client_entry);
   if (client_entry->internal.ke)
     silc_client_abort_key_agreement(client, conn, client_entry);
-  silc_atomic_uninit8(&client_entry->internal.refcnt);
+  silc_atomic_uninit16(&client_entry->internal.refcnt);
   silc_rwlock_free(client_entry->internal.lock);
   silc_free(client_entry);
 }
@@ -1010,7 +1010,7 @@ SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn,
   if (!client_entry)
     return FALSE;
 
-  if (silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) > 0)
+  if (silc_atomic_sub_int16(&client_entry->internal.refcnt, 1) > 0)
     return FALSE;
 
   SILC_LOG_DEBUG(("Deleting client %p", client_entry));
@@ -1072,10 +1072,10 @@ SilcClientEntry silc_client_ref_client(SilcClient client,
                                       SilcClientConnection conn,
                                       SilcClientEntry client_entry)
 {
-  silc_atomic_add_int8(&client_entry->internal.refcnt, 1);
+  silc_atomic_add_int16(&client_entry->internal.refcnt, 1);
   SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
-                 silc_atomic_get_int8(&client_entry->internal.refcnt) - 1,
-                 silc_atomic_get_int8(&client_entry->internal.refcnt)));
+                 silc_atomic_get_int16(&client_entry->internal.refcnt) - 1,
+                 silc_atomic_get_int16(&client_entry->internal.refcnt)));
   return client_entry;
 }
 
@@ -1086,8 +1086,8 @@ void silc_client_unref_client(SilcClient client, SilcClientConnection conn,
 {
   if (client_entry) {
     SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
-                   silc_atomic_get_int8(&client_entry->internal.refcnt),
-                   silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
+                   silc_atomic_get_int16(&client_entry->internal.refcnt),
+                   silc_atomic_get_int16(&client_entry->internal.refcnt) - 1));
     silc_client_del_client(client, conn, client_entry);
   }
 }
index 8b48e733196ac41ba63ae6c8c09684a9c7c5bc68..fd04fa3b0749477f60bd11dd8f2841806c33e651 100644 (file)
@@ -185,8 +185,10 @@ silc_client_add_connection(SilcClient client,
                           char *remote_host, int port,
                           SilcClientConnectCallback callback,
                           void *context);
-SilcBuffer silc_client_attributes_process(SilcClient client,
-                                          SilcClientConnection conn,
-                                          SilcDList attrs);
+void silc_client_attributes_process(SilcClient client,
+                                   SilcClientConnection conn,
+                                   SilcDList attrs,
+                                   SilcPKCSSignCb sign_cb,
+                                   void *context);
 
 #endif /* CLIENT_INTERNAL_H */
index 2242fd34d28a54ad812b5885c6133e09c21fd2dc..a29ad586ad57e268ba8c924269576f1163ad8289 100644 (file)
 
 /************************** Private Message Send ****************************/
 
+typedef struct {
+  SilcClient client;
+  SilcClientConnection conn;
+  SilcClientEntry client_entry;
+} *SilcClientPrvmsgContext;
+
+/* Message payload encoding callback */
+
+static void silc_client_send_private_message_final(SilcBuffer message,
+                                                  void *context)
+{
+  SilcClientPrvmsgContext p = context;
+
+  /* Send the private message packet */
+  if (message)
+    silc_packet_send_ext(p->conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
+                        p->client_entry->internal.send_key ?
+                        SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
+                        0, NULL, SILC_ID_CLIENT, &p->client_entry->id,
+                        silc_buffer_datalen(message), NULL, NULL);
+
+  silc_client_unref_client(p->client, p->conn, p->client_entry);
+  silc_free(p);
+}
+
 /* Sends private message to remote client. */
 
 SilcBool silc_client_send_private_message(SilcClient client,
@@ -34,8 +59,7 @@ SilcBool silc_client_send_private_message(SilcClient client,
                                          unsigned char *data,
                                          SilcUInt32 data_len)
 {
-  SilcBuffer buffer;
-  SilcBool ret;
+  SilcClientPrvmsgContext p;
   SilcID sid, rid;
 
   if (silc_unlikely(!client || !conn || !client_entry))
@@ -52,29 +76,25 @@ SilcBool silc_client_send_private_message(SilcClient client,
   rid.type = SILC_ID_CLIENT;
   rid.u.client_id = client_entry->id;
 
-  /* Encode private message payload */
-  buffer =
-    silc_message_payload_encode(flags, data, data_len,
-                               (!client_entry->internal.send_key ? FALSE :
-                                !client_entry->internal.generated),
-                               TRUE, client_entry->internal.send_key,
-                               client_entry->internal.hmac_send,
-                               client->rng, NULL, conn->private_key,
-                               hash, &sid, &rid, NULL);
-  if (silc_unlikely(!buffer)) {
-    SILC_LOG_ERROR(("Error encoding private message"));
+  p = silc_calloc(1, sizeof(*p));
+  if (!p)
     return FALSE;
-  }
 
-  /* Send the private message packet */
-  ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
-                            client_entry->internal.send_key ?
-                            SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
-                            0, NULL, SILC_ID_CLIENT, &client_entry->id,
-                            silc_buffer_datalen(buffer), NULL, NULL);
+  p->client = client;
+  p->conn = conn;
+  p->client_entry = silc_client_ref_client(client, conn, client_entry);
 
-  silc_buffer_free(buffer);
-  return ret;
+  /* Encode private message payload */
+  silc_message_payload_encode(flags, data, data_len,
+                             (!client_entry->internal.send_key ? FALSE :
+                              !client_entry->internal.generated),
+                             TRUE, client_entry->internal.send_key,
+                             client_entry->internal.hmac_send,
+                             client->rng, NULL, conn->private_key,
+                             hash, &sid, &rid, NULL,
+                             silc_client_send_private_message_final, p);
+
+  return TRUE;
 }
 
 /************************* Private Message Receive **************************/
index 9bf29987c7a0332ffa724633527d771c151d469b..81c9d6af430a0ce86eb7589c0063c2d3cf54de24 100644 (file)
@@ -28,7 +28,10 @@ typedef struct {
   SilcClient client;
   SilcClientConnection conn;
   SilcBufferStruct detach;
+  SilcBuffer auth;
   char *nickname;
+  unsigned char *id;
+  SilcUInt32 id_len;
   SilcUInt32 channel_count;
 } *SilcClientResumeSession;
 
@@ -68,6 +71,23 @@ silc_client_resume_command_callback(SilcClient client,
   va_end(ap);
 }
 
+/* Resume authentication data generation callback */
+
+static void silc_client_resume_auth_generated(const SilcBuffer data,
+                                             void *context)
+{
+  SilcClientConnection conn = context;
+  SilcClientResumeSession resume =
+    silc_fsm_get_state_context(&conn->internal->event_thread);
+
+  if (!data)
+    silc_fsm_next(&conn->internal->event_thread, silc_client_st_resume_error);
+  else
+    resume->auth = silc_buffer_copy(data);
+
+  SILC_FSM_CALL_CONTINUE_SYNC(&conn->internal->event_thread);
+}
+
 
 /****************************** NEW_ID packet *******************************/
 
@@ -279,7 +299,6 @@ SILC_FSM_STATE(silc_client_st_resume)
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
   SilcClientResumeSession resume;
-  SilcBuffer auth;
   unsigned char *id;
   SilcUInt16 id_len;
   SilcClientID client_id;
@@ -323,25 +342,34 @@ SILC_FSM_STATE(silc_client_st_resume)
     silc_fsm_next(fsm, silc_client_st_resume_error);
     return SILC_FSM_CONTINUE;
   }
+  resume->id = id;
+  resume->id_len = id_len;
 
   /* Generate authentication data that server will verify */
-  auth = silc_auth_public_key_auth_generate(conn->public_key,
-                                           conn->private_key,
-                                           client->rng,
-                                           conn->internal->hash,
-                                           &client_id, SILC_ID_CLIENT);
-  if (!auth) {
-    /** Out of memory */
-    silc_fsm_next(fsm, silc_client_st_resume_error);
-    return SILC_FSM_CONTINUE;
-  }
+  silc_fsm_next(fsm, silc_client_st_resume_send);
+  SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                conn->public_key, conn->private_key,
+                                client->rng, conn->internal->hash,
+                                &client_id, SILC_ID_CLIENT,
+                                silc_client_resume_auth_generated, conn));
+  /* NOT REACHED */
+}
+
+/* Send RESUME_CLIENT packet */
+
+SILC_FSM_STATE(silc_client_st_resume_send)
+{
+  SilcClientConnection conn = fsm_context;
+  SilcClientResumeSession resume = state_context;
+
+  SILC_LOG_DEBUG(("Send RESUME_CLIENT packet"));
 
   /* Send RESUME_CLIENT packet to resume to network */
   if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
-                          SILC_STR_UI_SHORT(id_len),
-                          SILC_STR_DATA(id, id_len),
-                          SILC_STR_DATA(silc_buffer_data(auth),
-                                        silc_buffer_len(auth)),
+                          SILC_STR_UI_SHORT(resume->id_len),
+                          SILC_STR_DATA(resume->id, resume->id_len),
+                          SILC_STR_DATA(silc_buffer_data(resume->auth),
+                                        silc_buffer_len(resume->auth)),
                           SILC_STR_END)) {
     /** Error sending packet */
     SILC_LOG_DEBUG(("Error sending packet"));
index 37a8c7c8a54d4fbdc5f933dceddc821939110297..e8e2db6238bfb7b6ee313d014ed9276985549aa4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2006 Pekka Riikonen
+  Copyright (C) 2006 - 2007 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
@@ -25,6 +25,7 @@ SILC_FSM_STATE(silc_client_st_register);
 SILC_FSM_STATE(silc_client_st_register_complete);
 SILC_FSM_STATE(silc_client_st_register_error);
 SILC_FSM_STATE(silc_client_st_resume);
+SILC_FSM_STATE(silc_client_st_resume_send);
 SILC_FSM_STATE(silc_client_st_resume_resolve_channels);
 SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes);
 SILC_FSM_STATE(silc_client_st_resume_completed);
index 85e33fe38217f0fe7b17c6c70a97270b1d3e2aca..d3220d54e58d9892d6700d57d54e56b6bf9e5f92 100644 (file)
@@ -721,7 +721,7 @@ SILC_FSM_STATE(silc_client_command_whois)
       goto out;
       break;
     }
-    obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
+    obj.data = silc_pkcs_public_key_encode(NULL, pk, &obj.data_len);
 
     attrs = silc_attribute_payload_encode(attrs,
                                           SILC_ATTRIBUTE_USER_PUBLIC_KEY,
@@ -1084,7 +1084,7 @@ SILC_FSM_STATE(silc_client_command_invite)
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
     if (pubkey) {
-      chidp = silc_public_key_payload_encode(pubkey);
+      chidp = silc_public_key_payload_encode(NULL, pubkey);
       args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
                                              silc_buffer_len(chidp), 2);
       silc_buffer_free(chidp);
@@ -1176,6 +1176,55 @@ SILC_FSM_STATE(silc_client_command_quit)
 
 /********************************** KILL ************************************/
 
+/* Signature callback */
+
+static void silc_client_command_kill_signed(const SilcBuffer buffer,
+                                           void *context)
+{
+  SilcClientCommandContext cmd = context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  silc_fsm_set_state_context(&cmd->thread, buffer);
+  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
+}
+
+/* Send KILL command */
+
+SILC_FSM_STATE(silc_client_command_kill_send)
+{
+  SilcClientCommandContext cmd = fsm_context;
+  SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
+  SilcBuffer idp, auth = state_context;
+  SilcClientEntry target = cmd->context;
+  char *comment = NULL;
+
+  if (cmd->argc >= 3)
+    if (strcasecmp(cmd->argv[2], "-pubkey"))
+      comment = cmd->argv[2];
+
+  /* Send the KILL command to the server */
+  idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
+  silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
+                             1, silc_buffer_datalen(idp),
+                             2, comment, comment ? strlen(comment) : 0,
+                             3, silc_buffer_datalen(auth));
+
+  silc_buffer_free(idp);
+  silc_client_unref_client(client, conn, target);
+
+  /* Notify application */
+  COMMAND(SILC_STATUS_OK);
+
+  /** Wait for command reply */
+  silc_fsm_next(fsm, silc_client_command_reply_wait);
+  return SILC_FSM_CONTINUE;
+}
+
 /* Command KILL. Router operator can use this command to remove an client
    fromthe SILC Network. */
 
@@ -1184,10 +1233,9 @@ SILC_FSM_STATE(silc_client_command_kill)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcBuffer idp, auth = NULL;
   SilcClientEntry target;
   SilcDList clients;
-  char *nickname = NULL, *comment = NULL;
+  char *nickname = NULL;
 
   if (cmd->argc < 2) {
     SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
@@ -1209,38 +1257,30 @@ SILC_FSM_STATE(silc_client_command_kill)
                                          cmd));
 
   target = silc_dlist_get(clients);
+  cmd->context = silc_client_ref_client(client, conn, target);
 
-  if (cmd->argc >= 3) {
-    if (strcasecmp(cmd->argv[2], "-pubkey"))
-      comment = cmd->argv[2];
+  silc_free(nickname);
+  silc_client_list_free(client, conn, clients);
 
+  /** Send KILL */
+  silc_fsm_next(fsm, silc_client_command_kill_send);
+
+  if (cmd->argc >= 3) {
     if (!strcasecmp(cmd->argv[2], "-pubkey") ||
        (cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
       /* Encode the public key authentication payload */
-      auth = silc_auth_public_key_auth_generate(conn->public_key,
-                                               conn->private_key,
-                                               conn->client->rng,
-                                               conn->internal->sha1hash,
-                                               &target->id, SILC_ID_CLIENT);
+      SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                        conn->public_key,
+                                        conn->private_key,
+                                        conn->client->rng,
+                                        conn->internal->sha1hash,
+                                        &target->id, SILC_ID_CLIENT,
+                                        silc_client_command_kill_signed,
+                                        cmd));
+      /* NOT REACHED */
     }
   }
 
-  /* Send the KILL command to the server */
-  idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
-  silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
-                             1, silc_buffer_datalen(idp),
-                             2, comment, comment ? strlen(comment) : 0,
-                             3, silc_buffer_datalen(auth));
-  silc_buffer_free(idp);
-  silc_buffer_free(auth);
-  silc_free(nickname);
-  silc_client_list_free(client, conn, clients);
-
-  /* Notify application */
-  COMMAND(SILC_STATUS_OK);
-
-  /** Wait for command reply */
-  silc_fsm_next(fsm, silc_client_command_reply_wait);
   return SILC_FSM_CONTINUE;
 }
 
@@ -1323,6 +1363,33 @@ SILC_FSM_STATE(silc_client_command_ping)
 
 /********************************** JOIN ************************************/
 
+typedef struct {
+  int type;
+  SilcBuffer auth;
+  SilcBuffer cauth;
+} *SilcClientJoinContext;
+
+/* Signature callback */
+
+static void silc_client_command_join_signed(const SilcBuffer buffer,
+                                           void *context)
+{
+  SilcClientCommandContext cmd = context;
+  SilcClientJoinContext j = cmd->context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  if (!j->type)
+    j->auth = silc_buffer_copy(buffer);
+  else
+    j->cauth = silc_buffer_copy(buffer);
+
+  SILC_FSM_CALL_CONTINUE(&cmd->thread);
+}
+
 /* Command JOIN. Joins to a channel. */
 
 SILC_FSM_STATE(silc_client_command_join)
@@ -1331,6 +1398,7 @@ SILC_FSM_STATE(silc_client_command_join)
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcChannelEntry channel = NULL;
+  SilcClientJoinContext j = cmd->context;
   SilcBuffer auth = NULL, cauth = NULL;
   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
   int i, passphrase_len = 0;
@@ -1369,46 +1437,76 @@ SILC_FSM_STATE(silc_client_command_join)
     } else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
       hmac = cmd->argv[++i];
     } else if (!strcasecmp(cmd->argv[i], "-founder")) {
-      auth = silc_auth_public_key_auth_generate(conn->public_key,
-                                               conn->private_key,
-                                               conn->client->rng,
-                                               conn->internal->sha1hash,
-                                               conn->local_id,
-                                               SILC_ID_CLIENT);
+      if (!j || !j->auth) {
+       if (!j) {
+         j = silc_calloc(1, sizeof(*j));
+         if (!j)
+           goto out;
+         cmd->context = j;
+       }
+       j->type = 0;
+       silc_free(passphrase);
+       silc_client_unref_channel(client, conn, channel);
+       SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                          conn->public_key,
+                                          conn->private_key,
+                                          conn->client->rng,
+                                          conn->internal->sha1hash,
+                                          conn->local_id,
+                                          SILC_ID_CLIENT,
+                                          silc_client_command_join_signed,
+                                          cmd));
+       /* NOT REACHED */
+      }
     } else if (!strcasecmp(cmd->argv[i], "-auth")) {
       SilcPublicKey pubkey = conn->public_key;
       SilcPrivateKey privkey = conn->private_key;
-      unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
+      unsigned char *pk, pkhash[SILC_HASH_MAXLEN], pubdata[128];
       SilcUInt32 pk_len;
 
-      if (cmd->argc >= i + 3) {
-       char *pass = "";
-       if (cmd->argc >= i + 4) {
-         pass = cmd->argv[i + 3];
-         i++;
+      if (!j || !j->cauth) {
+       if (!j) {
+         j = silc_calloc(1, sizeof(*j));
+         if (!j)
+           goto out;
+         cmd->context = j;
        }
-       if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
-                               &pubkey, &privkey)) {
-         SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
-             "Could not load key pair, check your arguments");
-         COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-         goto out;
+
+       if (cmd->argc >= i + 3) {
+         char *pass = "";
+         if (cmd->argc >= i + 4) {
+           pass = cmd->argv[i + 3];
+           i++;
+         }
+         if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
+                                 &pubkey, &privkey)) {
+           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+               "Could not load key pair, check your arguments");
+           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+           goto out;
+         }
+         i += 2;
        }
-       i += 2;
-      }
 
-      pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
-      silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
-      silc_free(pk);
-      pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
-      memcpy(pubdata, pkhash, 20);
-      cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
-                                                     pubdata, 128,
-                                                     conn->internal->sha1hash,
-                                                     conn->local_id,
-                                                     SILC_ID_CLIENT);
-      memset(pubdata, 0, 128);
-      silc_free(pubdata);
+       j->type = 1;
+       pk = silc_pkcs_public_key_encode(NULL, pubkey, &pk_len);
+       silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
+       silc_free(pk);
+       silc_rng_get_rn_data(conn->client->rng, sizeof(pubdata), pubdata,
+                            sizeof(pubdata));
+       memcpy(pubdata, pkhash, 20);
+       silc_free(passphrase);
+       silc_client_unref_channel(client, conn, channel);
+       SILC_FSM_CALL(silc_auth_public_key_auth_generate_wpub(
+                                          pubkey, privkey,
+                                          pubdata, sizeof(pubdata),
+                                          conn->internal->sha1hash,
+                                          conn->local_id,
+                                          SILC_ID_CLIENT,
+                                          silc_client_command_join_signed,
+                                          cmd));
+       /* NOT REACHED */
+      }
     } else {
       /* Passphrases must be UTF-8 encoded, so encode if it is not */
       if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
@@ -1436,12 +1534,15 @@ SILC_FSM_STATE(silc_client_command_join)
                              6, silc_buffer_datalen(auth),
                              7, silc_buffer_datalen(cauth));
 
-  silc_buffer_free(auth);
-  silc_buffer_free(cauth);
   if (passphrase)
     memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
   silc_client_unref_channel(client, conn, channel);
+  if (j) {
+    silc_buffer_free(j->auth);
+    silc_buffer_free(j->cauth);
+    silc_free(j);
+  }
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -1630,6 +1731,22 @@ SILC_FSM_STATE(silc_client_command_umode)
 
 /********************************** CMODE ***********************************/
 
+/* Signature callback */
+
+static void silc_client_command_cmode_signed(const SilcBuffer buffer,
+                                            void *context)
+{
+  SilcClientCommandContext cmd = context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  silc_fsm_set_state_context(&cmd->thread, buffer);
+  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
+}
+
 /* CMODE command. Sets channel mode. Modes that does not require any arguments
    can be set several at once. Those modes that require argument must be set
    separately (unless set with modes that does not require arguments). */
@@ -1639,8 +1756,9 @@ SILC_FSM_STATE(silc_client_command_cmode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
+  SilcBuffer auth = state_context;
   SilcChannelEntry channel = NULL;
-  SilcBuffer chidp, auth = NULL, pk = NULL;
+  SilcBuffer chidp, pk = NULL;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   SilcUInt32 mode, add, type, len, arg_len = 0;
   int i;
@@ -1797,31 +1915,38 @@ SILC_FSM_STATE(silc_client_command_cmode)
       break;
     case 'f':
       if (add) {
-       SilcPublicKey pubkey = conn->public_key;
-       SilcPrivateKey privkey = conn->private_key;
-
-       mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
-       type = 7;
-
-       if (cmd->argc >= 5) {
-         char *pass = "";
-         if (cmd->argc >= 6)
-           pass = cmd->argv[5];
-         if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
-                                 &pubkey, &privkey)) {
-           SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
-               "Could not load key pair, check your arguments");
-           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-           goto out;
+       if (!auth) {
+         SilcPublicKey pubkey = conn->public_key;
+         SilcPrivateKey privkey = conn->private_key;
+
+         mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
+         type = 7;
+
+         if (cmd->argc >= 5) {
+           char *pass = "";
+           if (cmd->argc >= 6)
+             pass = cmd->argv[5];
+           if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
+                                   &pubkey, &privkey)) {
+             SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+                 "Could not load key pair, check your arguments");
+             COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+             goto out;
+           }
          }
-       }
 
-       pk = silc_public_key_payload_encode(pubkey);
-       auth = silc_auth_public_key_auth_generate(pubkey, privkey,
-                                                 conn->client->rng,
-                                                 conn->internal->sha1hash,
-                                                 conn->local_id,
-                                                 SILC_ID_CLIENT);
+         pk = silc_public_key_payload_encode(NULL, pubkey);
+         silc_client_unref_channel(client, conn, channel);
+         SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                            pubkey, privkey,
+                                            conn->client->rng,
+                                            conn->internal->sha1hash,
+                                            conn->local_id,
+                                            SILC_ID_CLIENT,
+                                            silc_client_command_cmode_signed,
+                                            cmd));
+         /* NOT REACHED */
+       }
        arg = silc_buffer_data(auth);
        arg_len = silc_buffer_len(auth);
       } else {
@@ -1874,7 +1999,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
          }
 
          if (chpk) {
-           pk = silc_public_key_payload_encode(chpk);
+           pk = silc_public_key_payload_encode(NULL, chpk);
            auth = silc_argument_payload_encode_one(auth,
                                                    silc_buffer_datalen(pk),
                                                    chadd ? 0x00 : 0x01);
@@ -1933,6 +2058,22 @@ SILC_FSM_STATE(silc_client_command_cmode)
 
 /********************************* CUMODE ***********************************/
 
+/* Signature callback */
+
+static void silc_client_command_cumode_signed(const SilcBuffer buffer,
+                                             void *context)
+{
+  SilcClientCommandContext cmd = context;
+
+  if (!buffer) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
+  silc_fsm_set_state_context(&cmd->thread, buffer);
+  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
+}
+
 /* CUMODE command. Changes client's mode on a channel. */
 
 SILC_FSM_STATE(silc_client_command_cumode)
@@ -1940,10 +2081,11 @@ SILC_FSM_STATE(silc_client_command_cumode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
+  SilcBuffer auth = state_context;
   SilcChannelEntry channel = NULL;
   SilcChannelUser chu;
   SilcClientEntry client_entry;
-  SilcBuffer clidp, chidp, auth = NULL;
+  SilcBuffer clidp, chidp;
   SilcDList clients = NULL;
   unsigned char *name, *cp, modebuf[4];
   SilcUInt32 mode = 0, add, len;
@@ -2017,27 +2159,38 @@ SILC_FSM_STATE(silc_client_command_cumode)
       break;
     case 'f':
       if (add) {
-       SilcPublicKey pubkey = conn->public_key;
-       SilcPrivateKey privkey = conn->private_key;
-
-       if (cmd->argc >= 6) {
-         char *pass = "";
-         if (cmd->argc >= 7)
-           pass = cmd->argv[6];
-         if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
-                                 &pubkey, &privkey)) {
-           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
-               "Could not load key pair, check your arguments");
-           COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-           goto out;
+       if (!auth) {
+         SilcPublicKey pubkey = conn->public_key;
+         SilcPrivateKey privkey = conn->private_key;
+
+         if (cmd->argc >= 6) {
+           char *pass = "";
+           if (cmd->argc >= 7)
+             pass = cmd->argv[6];
+           if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
+                                   &pubkey, &privkey)) {
+             SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+                 "Could not load key pair, check your arguments");
+             COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+             goto out;
+           }
          }
+
+         silc_free(nickname);
+         silc_client_list_free(client, conn, clients);
+         silc_client_unref_channel(client, conn, channel);
+
+         SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                            pubkey, privkey,
+                                            conn->client->rng,
+                                            conn->internal->sha1hash,
+                                            conn->local_id,
+                                            SILC_ID_CLIENT,
+                                            silc_client_command_cumode_signed,
+                                            cmd));
+         /* NOT REACHED */
        }
 
-       auth = silc_auth_public_key_auth_generate(pubkey, privkey,
-                                                 conn->client->rng,
-                                                 conn->internal->sha1hash,
-                                                 conn->local_id,
-                                                 SILC_ID_CLIENT);
        mode |= SILC_CHANNEL_UMODE_CHANFO;
       } else {
        mode &= ~SILC_CHANNEL_UMODE_CHANFO;
@@ -2211,6 +2364,7 @@ SILC_FSM_STATE(silc_client_command_kick)
 typedef struct {
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
+  SilcBuffer auth;
 } *SilcClientCommandOper;
 
 /* Ask passphrase callback */
@@ -2229,6 +2383,19 @@ static void silc_client_command_oper_cb(const unsigned char *data,
   SILC_FSM_CALL_CONTINUE(&cmd->thread);
 }
 
+static void silc_client_command_oper_sign_cb(const SilcBuffer data,
+                                            void *context)
+{
+  SilcClientCommandContext cmd = context;
+  SilcClientCommandOper oper = cmd->context;
+
+  if (data)
+    oper->auth = silc_buffer_copy(data);
+
+  /* Continue */
+  SILC_FSM_CALL_CONTINUE(&cmd->thread);
+}
+
 /* Send OPER/SILCOPER command */
 
 SILC_FSM_STATE(silc_client_command_oper_send)
@@ -2236,21 +2403,7 @@ SILC_FSM_STATE(silc_client_command_oper_send)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClientCommandOper oper = cmd->context;
-  SilcBuffer auth;
-
-  if (!oper || !oper->passphrase) {
-    /* Encode the public key authentication payload */
-    auth = silc_auth_public_key_auth_generate(conn->public_key,
-                                             conn->private_key,
-                                             conn->client->rng,
-                                             conn->internal->hash,
-                                             conn->local_id,
-                                             SILC_ID_CLIENT);
-  } else {
-    /* Encode the password authentication payload */
-    auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
-                                   oper->passphrase, oper->passphrase_len);
-  }
+  SilcBuffer auth = oper ? oper->auth : NULL;
 
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
                              1, cmd->argv[1], strlen(cmd->argv[1]),
@@ -2271,6 +2424,36 @@ SILC_FSM_STATE(silc_client_command_oper_send)
   return SILC_FSM_CONTINUE;
 }
 
+/* Get authentication data */
+
+SILC_FSM_STATE(silc_client_command_oper_get_auth)
+{
+  SilcClientCommandContext cmd = fsm_context;
+  SilcClientConnection conn = cmd->conn;
+  SilcClientCommandOper oper = cmd->context;
+
+  silc_fsm_next(fsm, silc_client_command_oper_send);
+
+  if (!oper || !oper->passphrase) {
+    /* Encode the public key authentication payload */
+    SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+                                      conn->public_key,
+                                      conn->private_key,
+                                      conn->client->rng,
+                                      conn->internal->hash,
+                                      conn->local_id, SILC_ID_CLIENT,
+                                      silc_client_command_oper_sign_cb,
+                                      oper));
+    /* NOT REACHED */
+  }
+
+  /* Encode the password authentication payload */
+  oper->auth = silc_auth_payload_encode(NULL, SILC_AUTH_PASSWORD, NULL, 0,
+                                       oper->passphrase, oper->passphrase_len);
+
+  return SILC_FSM_CONTINUE;
+}
+
 /* OPER command. Used to obtain server operator privileges. */
 
 SILC_FSM_STATE(silc_client_command_oper)
@@ -2286,7 +2469,7 @@ SILC_FSM_STATE(silc_client_command_oper)
     return SILC_FSM_FINISH;
   }
 
-  silc_fsm_next(fsm, silc_client_command_oper_send);
+  silc_fsm_next(fsm, silc_client_command_oper_get_auth);
 
   /* Get passphrase */
   if (cmd->argc < 3) {
@@ -2393,7 +2576,7 @@ SILC_FSM_STATE(silc_client_command_ban)
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
     if (pubkey) {
-      chidp = silc_public_key_payload_encode(pubkey);
+      chidp = silc_public_key_payload_encode(NULL, pubkey);
       args = silc_argument_payload_encode_one(args,
                                              silc_buffer_datalen(chidp), 2);
       silc_buffer_free(chidp);
@@ -2492,7 +2675,7 @@ SILC_FSM_STATE(silc_client_command_watch)
     silc_buffer_format(args,
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
-    buffer = silc_public_key_payload_encode(pk);
+    buffer = silc_public_key_payload_encode(NULL, pk);
     args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
                                            pubkey_add ? 0x00 : 0x01);
     silc_buffer_free(buffer);
@@ -2827,17 +3010,60 @@ void silc_client_commands_unregister(SilcClient client)
 
 /****************** Client Side Incoming Command Handling *******************/
 
-/* Reply to WHOIS command from server */
+typedef struct {
+  SilcClientConnection conn;
+  SilcUInt16 cmd_ident;
+} *SilcClientProcessWhois;
+
+/* Send reply to WHOIS from server */
+
+static void
+silc_client_command_process_whois_send(SilcBool success,
+                                      const unsigned char *data,
+                                      SilcUInt32 data_len, void *context)
+{
+  SilcClientProcessWhois w = context;
+  SilcBufferStruct buffer;
+  SilcBuffer packet;
+
+  if (!data) {
+    silc_free(w);
+    return;
+  }
+
+  silc_buffer_set(&buffer, (unsigned char *)data, data_len);
+
+  /* Send the attributes back in COMMAND_REPLY packet */
+  packet =
+    silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                        SILC_STATUS_OK, 0, w->cmd_ident,
+                                        1, 11, buffer.data,
+                                        silc_buffer_len(&buffer));
+  if (!packet) {
+    silc_free(w);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
+
+  silc_packet_send(w->conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  silc_buffer_datalen(packet));
+
+  silc_buffer_free(packet);
+  silc_free(w);
+}
+
+/* Process WHOIS command from server */
 
 static void silc_client_command_process_whois(SilcClient client,
                                              SilcClientConnection conn,
                                              SilcCommandPayload payload,
                                              SilcArgumentPayload args)
 {
+  SilcClientProcessWhois w;
   SilcDList attrs;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
-  SilcBuffer buffer, packet;
 
   SILC_LOG_DEBUG(("Received WHOIS command"));
 
@@ -2850,32 +3076,18 @@ static void silc_client_command_process_whois(SilcClient client,
   if (!attrs)
     return;
 
-  /* Process requested attributes */
-  buffer = silc_client_attributes_process(client, conn, attrs);
-  if (!buffer) {
+  w = silc_calloc(1, sizeof(*w));
+  if (!w) {
     silc_attribute_payload_list_free(attrs);
     return;
   }
+  w->conn = conn;
+  w->cmd_ident = silc_command_get_ident(payload);
 
-  /* Send the attributes back in COMMAND_REPLY packet */
-  packet =
-    silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                        SILC_STATUS_OK, 0,
-                                        silc_command_get_ident(payload),
-                                        1, 11, buffer->data,
-                                        silc_buffer_len(buffer));
-  if (!packet) {
-    silc_buffer_free(buffer);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
-
-  silc_packet_send(conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
-                  silc_buffer_datalen(packet));
-
-  silc_buffer_free(packet);
-  silc_buffer_free(buffer);
+  /* Process requested attributes */
+  silc_client_attributes_process(client, conn, attrs,
+                                silc_client_command_process_whois_send, w);
+  silc_attribute_payload_list_free(attrs);
 }
 
 /* Client is able to receive some command packets even though they are
index 898204a18f46663a571c0c38202d924fb9d3f089..6f28ab962a4ab3e2dc2bdba3e97ac1c19ba8ca5f 100644 (file)
@@ -701,9 +701,9 @@ typedef struct SilcClientParamsStruct {
      not all SILC server versions return such channel name strings. */
   SilcBool full_channel_names;
 
-  /* If this is set to TRUE, the silcclient library will not register and
-     deregister the cipher, pkcs, hash and hmac algorithms. The application
-     itself will need to handle that. */
+  /* If this is set to TRUE, the silcclient library will not initialize
+     or uninitialize the SILC Crypto Toolkit.  The application will have
+     to do that itself by calling silc_crypto_init and silc_crypto_uninit. */
   SilcBool dont_register_crypto_library;
 
 } SilcClientParams;