From: Pekka Riikonen Date: Tue, 10 Jul 2007 17:21:13 +0000 (+0000) Subject: Added support for the new PKCS API, Auth API and other API X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=65bb39eb3f473859544469c209b6371e230ac9a2 Added support for the new PKCS API, Auth API and other API changes. --- diff --git a/CHANGES.RUNTIME b/CHANGES.RUNTIME index e8410c93..a2c6bdb9 100644 --- a/CHANGES.RUNTIME +++ b/CHANGES.RUNTIME @@ -1,3 +1,12 @@ +Tue Jul 10 20:02:04 EEST 2007 Pekka Riikonen + + * 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 * Added SILC Accelerator Library. Provides generic way to diff --git a/TODO b/TODO index dac3d03f..f32a2234 100644 --- 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 index 00000000..5949f029 --- /dev/null +++ b/apps/irssi/CHANGES @@ -0,0 +1,7 @@ +Tue Jul 10 20:13:47 EEST 2007 Pekka Riikonen + + * Added support for the new PKCS API. + +----------------------------------------------------------------------------- + +For older changes please see the CHANGES file from the CVS tree. diff --git a/apps/irssi/src/perl/silc/Makefile.PL.in b/apps/irssi/src/perl/silc/Makefile.PL.in index 9c1b0771..833cf402 100644 --- a/apps/irssi/src/perl/silc/Makefile.PL.in +++ b/apps/irssi/src/perl/silc/Makefile.PL.in @@ -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'); diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index 38e90d08..25afdb04 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -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 ? diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index 1c6bb8d9..8917fc2c 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -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); diff --git a/apps/irssi/src/silc/core/silc-core.c b/apps/irssi/src/silc/core/silc-core.c index 8b6f9f74..8253713d 100644 --- a/apps/irssi/src/silc/core/silc-core.c +++ b/apps/irssi/src/silc/core/silc-core.c @@ -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); diff --git a/apps/irssi/src/silc/core/silc-queries.c b/apps/irssi/src/silc/core/silc-queries.c index 271e3d5e..664eece6 100644 --- a/apps/irssi/src/silc/core/silc-queries.c +++ b/apps/irssi/src/silc/core/silc-queries.c @@ -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 { diff --git a/apps/irssi/src/silc/core/silc-servers.c b/apps/irssi/src/silc/core/silc-servers.c index e16fb02c..bfd5f600 100644 --- a/apps/irssi/src/silc/core/silc-servers.c +++ b/apps/irssi/src/silc/core/silc-servers.c @@ -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, ¶ms.detach_data_len); + params.detach_data = silc_file_readfile(file, ¶ms.detach_data_len, NULL); if (params.detach_data) params.detach_data[params.detach_data_len] = 0; if (params.detach_data) diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 9fef6df8..6a634b4f 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -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(); diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index ac1116d2..e008e44f 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -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 */ diff --git a/lib/silcclient/client_attrs.c b/lib/silcclient/client_attrs.c index 34902df0..4831ed31 100644 --- a/lib/silcclient/client_attrs.c +++ b/lib/silcclient/client_attrs.c @@ -22,6 +22,12 @@ #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, diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index 1d78d221..4fcfb08c 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -24,6 +24,29 @@ /************************** 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 **************************/ diff --git a/lib/silcclient/client_entry.c b/lib/silcclient/client_entry.c index 1f39eed2..d3d6e44d 100644 --- a/lib/silcclient/client_entry.c +++ b/lib/silcclient/client_entry.c @@ -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); } } diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index 8b48e733..fd04fa3b 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -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 */ diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 2242fd34..a29ad586 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -24,6 +24,31 @@ /************************** 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 **************************/ diff --git a/lib/silcclient/client_register.c b/lib/silcclient/client_register.c index 9bf29987..81c9d6af 100644 --- a/lib/silcclient/client_register.c +++ b/lib/silcclient/client_register.c @@ -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")); diff --git a/lib/silcclient/client_register.h b/lib/silcclient/client_register.h index 37a8c7c8..e8e2db62 100644 --- a/lib/silcclient/client_register.h +++ b/lib/silcclient/client_register.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - 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); diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 85e33fe3..d3220d54 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -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 diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 898204a1..6f28ab96 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -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;