X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fprotocol.c;h=4bf277c8a2e5759eb330a1b1e343fc487a097cf9;hb=a818c5b5411bbc4436d1c5f011236985c96bb787;hp=988620d8aa61d431a0a32e4734ed4ed64b80b3c2;hpb=163b51c85c9ebc70dd010557a8095a48545bb607;p=silc.git diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index 988620d8..4bf277c8 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -22,15 +22,14 @@ */ /* $Id$ */ -#include "clientlibincludes.h" +#include "silcincludes.h" +#include "silcclient.h" #include "client_internal.h" SILC_TASK_CALLBACK(silc_client_protocol_connection_auth); SILC_TASK_CALLBACK(silc_client_protocol_key_exchange); SILC_TASK_CALLBACK(silc_client_protocol_rekey); -extern char *silc_version_string; - /* * Key Exhange protocol functions */ @@ -52,29 +51,57 @@ void silc_client_protocol_ke_send_packet(SilcSKE ske, packet->data, packet->len, TRUE); } -/* Callback that is called when we have received KE2 payload from +/* Public key verification callback. Called by the application. */ + +typedef struct { + SilcSKE ske; + SilcSKEVerifyCbCompletion completion; + void *completion_context; +} *VerifyKeyContext; + +static void silc_client_verify_key_cb(bool success, void *context) +{ + VerifyKeyContext verify = (VerifyKeyContext)context; + + SILC_LOG_DEBUG(("Start")); + + /* Call the completion callback back to the SKE */ + verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK : + SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY, + verify->completion_context); + + silc_free(verify); +} + +/* Callback that is called when we have received KE payload from responder. We try to verify the public key now. */ -SilcSKEStatus silc_client_protocol_ke_verify_key(SilcSKE ske, - unsigned char *pk_data, - uint32 pk_len, - SilcSKEPKType pk_type, - void *context) +void silc_client_protocol_ke_verify_key(SilcSKE ske, + unsigned char *pk_data, + SilcUInt32 pk_len, + SilcSKEPKType pk_type, + void *context, + SilcSKEVerifyCbCompletion completion, + void *completion_context) { SilcProtocol protocol = (SilcProtocol)context; SilcClientKEInternalContext *ctx = (SilcClientKEInternalContext *)protocol->context; SilcClient client = (SilcClient)ctx->client; + VerifyKeyContext verify; SILC_LOG_DEBUG(("Start")); - /* Verify public key from user. */ - if (!client->ops->verify_public_key(client, ctx->sock->user_data, - ctx->sock->type, - pk_data, pk_len, pk_type)) - return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; + verify = silc_calloc(1, sizeof(*verify)); + verify->ske = ske; + verify->completion = completion; + verify->completion_context = completion_context; - return SILC_SKE_STATUS_OK; + /* Verify public key from user. */ + client->internal->ops->verify_public_key(client, ctx->sock->user_data, + ctx->sock->type, + pk_data, pk_len, pk_type, + silc_client_verify_key_cb, verify); } /* Sets the negotiated key material into use for particular connection. */ @@ -86,7 +113,8 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, SilcPKCS pkcs, SilcHash hash, SilcHmac hmac, - SilcSKEDiffieHellmanGroup group) + SilcSKEDiffieHellmanGroup group, + bool is_responder) { SilcClientConnection conn = (SilcClientConnection)sock->user_data; @@ -95,43 +123,43 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, /* Allocate cipher to be used in the communication */ silc_cipher_alloc(cipher->cipher->name, &conn->send_key); silc_cipher_alloc(cipher->cipher->name, &conn->receive_key); + silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send); + silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_receive); + + if (is_responder == TRUE) { + silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->send_key, keymat->receive_iv); + silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->receive_key, keymat->send_iv); + silc_hmac_set_key(conn->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(conn->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); + } else { + silc_cipher_set_key(conn->send_key, keymat->send_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->send_key, keymat->send_iv); + silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->receive_key, keymat->receive_iv); + silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); + } - conn->send_key->cipher->set_key(conn->send_key->context, - keymat->send_enc_key, - keymat->enc_key_len); - conn->send_key->set_iv(conn->send_key, keymat->send_iv); - conn->receive_key->cipher->set_key(conn->receive_key->context, - keymat->receive_enc_key, - keymat->enc_key_len); - conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv); - - /* Allocate PKCS to be used */ -#if 0 - /* XXX Do we ever need to allocate PKCS for the connection?? - If yes, we need to change KE protocol to get the initiators - public key. */ - silc_pkcs_alloc(pkcs->pkcs->name, &conn->public_Key); - silc_pkcs_set_public_key(conn->public_key, ske->ke2_payload->pk_data, - ske->ke2_payload->pk_len); -#endif - + /* Rekey stuff */ conn->rekey = silc_calloc(1, sizeof(*conn->rekey)); - conn->rekey->send_enc_key = - silc_calloc(keymat->enc_key_len / 8, - sizeof(*conn->rekey->send_enc_key)); - memcpy(conn->rekey->send_enc_key, - keymat->send_enc_key, keymat->enc_key_len / 8); + conn->rekey->send_enc_key = silc_memdup(keymat->send_enc_key, + keymat->enc_key_len / 8); conn->rekey->enc_key_len = keymat->enc_key_len / 8; if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS) conn->rekey->pfs = TRUE; conn->rekey->ske_group = silc_ske_group_get_number(group); - /* Save HMAC key to be used in the communication. */ - silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac_send); - silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, keymat->hmac_key_len); - conn->hmac_receive = conn->hmac_send; - /* Save the HASH function */ silc_hash_alloc(hash->hash->name, &conn->hash); } @@ -139,13 +167,13 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, /* Checks the version string of the server. */ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version, - uint32 len) + SilcUInt32 len, void *context) { SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data; SilcClient client = (SilcClient)ske->user_data; SilcSKEStatus status = SILC_SKE_STATUS_OK; char *cp; - int maj = 0, min = 0, build = 0, maj2, min2, build2; + int maj = 0, min = 0, build = 0, maj2 = 0, min2 = 0, build2 = 0; /* Check for initial version string */ if (!strstr(version, "SILC-1.0-")) @@ -167,7 +195,7 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version, if (cp) build = atoi(cp + 1); - cp = silc_version_string + 9; + cp = client->internal->silc_client_version + 9; if (!cp) status = SILC_SKE_STATUS_BAD_VERSION; @@ -183,18 +211,66 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version, if (maj != maj2) status = SILC_SKE_STATUS_BAD_VERSION; -#if 0 - if (min < min2) - status = SILC_SKE_STATUS_BAD_VERSION; -#endif + + /* XXX backward support for 0.6.1 */ + if (maj == 0 && min == 6 && build < 2) + ske->backward_version = 1; if (status != SILC_SKE_STATUS_OK) - client->ops->say(client, conn, - "We don't support server version `%s'", version); + client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, + "We don't support server version `%s'", + version); return status; } +/* Callback that is called by the SKE to indicate that it is safe to + continue the execution of the protocol. Is given as argument to the + silc_ske_initiator_finish or silc_ske_responder_phase_2 functions. + This is called due to the fact that the public key verification + process is asynchronous and we must not continue the protocl until + the public key has been verified and this callback is called. */ + +static void silc_client_protocol_ke_continue(SilcSKE ske, + void *context) +{ + SilcProtocol protocol = (SilcProtocol)context; + SilcClientKEInternalContext *ctx = + (SilcClientKEInternalContext *)protocol->context; + SilcClient client = (SilcClient)ctx->client; + SilcClientConnection conn = ctx->sock->user_data; + + SILC_LOG_DEBUG(("Start")); + + if (ske->status != SILC_SKE_STATUS_OK) { + /* Call failure client operation */ + client->internal->ops->failure(client, conn, protocol, + (void *)ske->status); + protocol->state = SILC_PROTOCOL_STATE_ERROR; + silc_protocol_execute(protocol, client->schedule, 0, 0); + return; + } + + /* Send Ok to the other end. We will end the protocol as server + sends Ok to us when we will take the new keys into use. Do this + if we are initiator. This is happens when this callback was sent + to silc_ske_initiator_finish function. */ + if (ctx->responder == FALSE) { + silc_ske_end(ctx->ske); + + /* End the protocol on the next round */ + protocol->state = SILC_PROTOCOL_STATE_END; + } + + /* Advance protocol state and call the next state if we are responder. + This happens when this callback was sent to silc_ske_responder_phase_2 + function. */ + if (ctx->responder == TRUE) { + protocol->state++; + silc_protocol_execute(protocol, client->schedule, 0, 100000); + } +} + /* Performs key exchange protocol. This is used for both initiator and responder key exchange. This may be called recursively. */ @@ -205,7 +281,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) (SilcClientKEInternalContext *)protocol->context; SilcClient client = (SilcClient)ctx->client; SilcClientConnection conn = ctx->sock->user_data; - SilcSKEStatus status = 0; + SilcSKEStatus status = SILC_SKE_STATUS_OK; SILC_LOG_DEBUG(("Start")); @@ -221,34 +297,40 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) SilcSKE ske; /* Allocate Key Exchange object */ - ske = silc_ske_alloc(); - ctx->ske = ske; - ske->rng = client->rng; - ske->user_data = (void *)client; + ctx->ske = ske = silc_ske_alloc(client->rng, client); + + silc_ske_set_callbacks(ske, ctx->send_packet, NULL, + ctx->verify, + silc_client_protocol_ke_continue, + silc_ske_check_version, + context); if (ctx->responder == TRUE) { /* Start the key exchange by processing the received security properties packet from initiator. */ - status = silc_ske_responder_start(ske, ctx->rng, ctx->sock, - silc_version_string, - ctx->packet->buffer, TRUE, - NULL, NULL); + status = + silc_ske_responder_start(ske, ctx->rng, ctx->sock, + client->internal->silc_client_version, + ctx->packet->buffer, TRUE); } else { SilcSKEStartPayload *start_payload; /* Assemble security properties. */ - silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE, - silc_version_string, - &start_payload); + silc_ske_assemble_security_properties( + ske, SILC_SKE_SP_FLAG_MUTUAL, + client->internal->silc_client_version, + &start_payload); /* Start the key exchange by sending our security properties to the remote end. */ status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock, - start_payload, - ctx->send_packet, - context); + start_payload); } + /* Return now if the procedure is pending */ + if (status == SILC_SKE_STATUS_PENDING) + return; + if (status != SILC_SKE_STATUS_OK) { SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol", status)); @@ -256,14 +338,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) status)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); return; } /* Advance protocol state and call the next state if we are responder */ protocol->state++; if (ctx->responder == TRUE) - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000); + silc_protocol_execute(protocol, client->schedule, 0, 100000); } break; case 2: @@ -273,18 +355,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) */ if (ctx->responder == TRUE) { /* Sends the selected security properties to the initiator. */ - status = - silc_ske_responder_phase_1(ctx->ske, - ctx->ske->start_payload, - ctx->send_packet, - context); + status = silc_ske_responder_phase_1(ctx->ske); } else { /* Call Phase-1 function. This processes the Key Exchange Start paylaod reply we just got from the responder. The callback function will receive the processed payload where we will save it. */ - status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer, - NULL, NULL); + status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer); } if (status != SILC_SKE_STATUS_OK) { @@ -294,14 +371,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) status)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); return; } /* Advance protocol state and call next state if we are initiator */ protocol->state++; if (ctx->responder == FALSE) - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000); + silc_protocol_execute(protocol, client->schedule, 0, 100000); } break; case 3: @@ -312,9 +389,9 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) if (ctx->responder == TRUE) { /* Process the received Key Exchange 1 Payload packet from the initiator. This also creates our parts of the Diffie - Hellman algorithm. */ - status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, - ctx->verify, context, NULL, NULL); + Hellman algorithm. The silc_client_protocol_ke_continue will + be called after the public key has been verified. */ + status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer); } else { /* Call the Phase-2 function. This creates Diffie Hellman key exchange parameters and sends our public part inside @@ -322,10 +399,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) status = silc_ske_initiator_phase_2(ctx->ske, client->public_key, client->private_key, - ctx->send_packet, - context); + SILC_SKE_PK_TYPE_SILC); + protocol->state++; } + /* Return now if the procedure is pending */ + if (status == SILC_SKE_STATUS_PENDING) + return; + if (status != SILC_SKE_STATUS_OK) { SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol", status)); @@ -333,14 +414,9 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) status)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); return; } - - /* Advance protocol state and call the next state if we are responder */ - protocol->state++; - if (ctx->responder == TRUE) - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000); } break; case 4: @@ -354,40 +430,37 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) status = silc_ske_responder_finish(ctx->ske, client->public_key, client->private_key, - SILC_SKE_PK_TYPE_SILC, - ctx->send_packet, - context); - status = 0; + SILC_SKE_PK_TYPE_SILC); + + /* End the protocol on the next round */ + protocol->state = SILC_PROTOCOL_STATE_END; } else { /* Finish the protocol. This verifies the Key Exchange 2 payload - sent by responder. */ - status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer, - ctx->verify, context, NULL, NULL); + sent by responder. The silc_client_protocol_ke_continue will + be called after the public key has been verified. */ + status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer); } - if (status != SILC_SKE_STATUS_OK) { + /* Return now if the procedure is pending */ + if (status == SILC_SKE_STATUS_PENDING) + return; + if (status != SILC_SKE_STATUS_OK) { if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) { - client->ops->say(client, conn, - "Received unsupported server %s public key", - ctx->sock->hostname); + client->internal->ops->say( + client, conn, SILC_CLIENT_MESSAGE_AUDIT, + "Received unsupported server %s public key", + ctx->sock->hostname); } else { - client->ops->say(client, conn, + client->internal->ops->say( + client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Error during key exchange protocol with server %s", ctx->sock->hostname); } protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); return; } - - /* Send Ok to the other end. We will end the protocol as server - sends Ok to us when we will take the new keys into use. */ - if (ctx->responder == FALSE) - silc_ske_end(ctx->ske, ctx->send_packet, context); - - /* End the protocol on the next round */ - protocol->state = SILC_PROTOCOL_STATE_END; } break; @@ -406,7 +479,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) keymat); if (status != SILC_SKE_STATUS_OK) { protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, client->schedule, 0, 300000); silc_ske_free_key_material(keymat); return; } @@ -415,17 +488,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) /* Send Ok to the other end if we are responder. If we are initiator we have sent this already. */ if (ctx->responder == TRUE) - silc_ske_end(ctx->ske, ctx->send_packet, context); + silc_ske_end(ctx->ske); /* Unregister the timeout task since the protocol has ended. This was the timeout task to be executed if the protocol is not completed fast enough. */ if (ctx->timeout_task) - silc_task_unregister(client->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(client->schedule, ctx->timeout_task); /* Protocol has ended, call the final callback */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); } @@ -437,12 +510,11 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) */ /* Send abort notification */ - silc_ske_abort(ctx->ske, ctx->ske->status, - ctx->send_packet, context); + silc_ske_abort(ctx->ske, ctx->ske->status); /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); break; @@ -456,11 +528,11 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) This was the timeout task to be executed if the protocol is not completed fast enough. */ if (ctx->timeout_task) - silc_task_unregister(client->timeout_queue, ctx->timeout_task); + silc_schedule_task_del(client->schedule, ctx->timeout_task); /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); break; @@ -475,26 +547,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) static int silc_client_get_public_key_auth(SilcClient client, - char *filepath, + SilcClientConnection conn, unsigned char *auth_data, - uint32 *auth_data_len, + SilcUInt32 *auth_data_len, SilcSKE ske) { int len; SilcPKCS pkcs; SilcBuffer auth; - SilcPublicKey pub_key; - - if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN)) - return FALSE; - silc_pkcs_alloc(pub_key->name, &pkcs); - if (!silc_pkcs_public_key_set(pkcs, pub_key)) { - silc_pkcs_free(pkcs); - silc_pkcs_public_key_free(pub_key); - return FALSE; - } + /* Use our default key */ + pkcs = client->pkcs; /* Make the authentication data. Protocol says it is HASH plus KE Start Payload. */ @@ -507,19 +570,52 @@ silc_client_get_public_key_auth(SilcClient client, ske->start_payload_copy->len), SILC_STR_END); - if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) { - silc_pkcs_free(pkcs); + if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, + auth->len, auth_data, auth_data_len)) { silc_buffer_free(auth); - silc_pkcs_public_key_free(pub_key); return TRUE; } - silc_pkcs_free(pkcs); silc_buffer_free(auth); - silc_pkcs_public_key_free(pub_key); return FALSE; } +/* Continues the connection authentication protocol. This funtion may + be called directly or used as SilcAskPassphrase callback. */ + +static void +silc_client_conn_auth_continue(unsigned char *auth_data, + SilcUInt32 auth_data_len, void *context) +{ + SilcProtocol protocol = (SilcProtocol)context; + SilcClientConnAuthInternalContext *ctx = + (SilcClientConnAuthInternalContext *)protocol->context; + SilcClient client = (SilcClient)ctx->client; + SilcBuffer packet; + int payload_len = 0; + + SILC_LOG_DEBUG(("Start")); + + payload_len = 4 + auth_data_len; + packet = silc_buffer_alloc(payload_len); + silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + silc_buffer_format(packet, + SILC_STR_UI_SHORT(payload_len), + SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT), + SILC_STR_UI_XNSTRING(auth_data, auth_data_len), + SILC_STR_END); + + /* Send the packet to server */ + silc_client_packet_send(client, ctx->sock, + SILC_PACKET_CONNECTION_AUTH, + NULL, 0, NULL, NULL, + packet->data, packet->len, TRUE); + silc_buffer_free(packet); + + /* Next state is end of protocol */ + protocol->state = SILC_PROTOCOL_STATE_END; +} + SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) { SilcProtocol protocol = (SilcProtocol)context; @@ -540,10 +636,9 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) * Start protocol. We send authentication data to the server * to be authenticated. */ - SilcBuffer packet; - int payload_len = 0; unsigned char *auth_data = NULL; - uint32 auth_data_len = 0; + SilcUInt32 auth_data_len = 0; + unsigned char sign[1024]; switch(ctx->auth_meth) { case SILC_AUTH_NONE: @@ -558,50 +653,32 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) break; } - client->ops->say(client, conn, - "Password authentication required by server %s", - ctx->sock->hostname); - auth_data = client->ops->ask_passphrase(client, conn); - auth_data_len = strlen(auth_data); + client->internal->ops->say( + client, conn, SILC_CLIENT_MESSAGE_INFO, + "Password authentication required by server %s", + ctx->sock->hostname); + client->internal->ops->ask_passphrase(client, conn, + silc_client_conn_auth_continue, + protocol); + return; break; case SILC_AUTH_PUBLIC_KEY: - { - unsigned char sign[1024]; - + if (!ctx->auth_data) { /* Public key authentication */ - silc_client_get_public_key_auth(client, ctx->auth_data, - sign, &auth_data_len, + silc_client_get_public_key_auth(client, conn, sign, &auth_data_len, ctx->ske); - auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); - memcpy(auth_data, sign, auth_data_len); - break; + auth_data = sign; + } else { + auth_data = ctx->auth_data; + auth_data_len = ctx->auth_data_len; } + + break; } - payload_len = 4 + auth_data_len; - packet = silc_buffer_alloc(payload_len); - silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); - silc_buffer_format(packet, - SILC_STR_UI_SHORT(payload_len), - SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT), - SILC_STR_UI_XNSTRING(auth_data, auth_data_len), - SILC_STR_END); - - /* Send the packet to server */ - silc_client_packet_send(client, ctx->sock, - SILC_PACKET_CONNECTION_AUTH, - NULL, 0, NULL, NULL, - packet->data, packet->len, TRUE); - - if (auth_data) { - memset(auth_data, 0, auth_data_len); - silc_free(auth_data); - } - silc_buffer_free(packet); - - /* Next state is end of protocol */ - protocol->state = SILC_PROTOCOL_STATE_END; + silc_client_conn_auth_continue(auth_data, + auth_data_len, protocol); } break; @@ -613,7 +690,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) /* Protocol has ended, call the final callback */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); } @@ -635,7 +712,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); } @@ -647,7 +724,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); break; @@ -677,41 +754,37 @@ silc_client_protocol_rekey_validate(SilcClient client, silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->send_key, keymat->receive_iv); + silc_hmac_set_key(conn->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->receive_key, keymat->send_iv); + silc_hmac_set_key(conn->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); } } else { if (send) { silc_cipher_set_key(conn->send_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->send_key, keymat->send_iv); + silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->receive_key, keymat->receive_iv); + silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); } } - if (send) { - silc_hmac_alloc(conn->hmac_receive->hmac->name, NULL, &conn->hmac_send); - silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, - keymat->hmac_key_len); - } else { - silc_hmac_free(conn->hmac_receive); - conn->hmac_receive = conn->hmac_send; - } - /* Save the current sending encryption key */ if (!send) { memset(conn->rekey->send_enc_key, 0, conn->rekey->enc_key_len); silc_free(conn->rekey->send_enc_key); - conn->rekey->send_enc_key = - silc_calloc(keymat->enc_key_len / 8, - sizeof(*conn->rekey->send_enc_key)); - memcpy(conn->rekey->send_enc_key, keymat->send_enc_key, - keymat->enc_key_len / 8); + conn->rekey->send_enc_key = silc_memdup(keymat->send_enc_key, + keymat->enc_key_len / 8); conn->rekey->enc_key_len = keymat->enc_key_len / 8; } } @@ -726,8 +799,8 @@ silc_client_protocol_rekey_generate(SilcClient client, { SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data; SilcSKEKeyMaterial *keymat; - uint32 key_len = silc_cipher_get_key_len(conn->send_key); - uint32 hash_len = conn->hash->hash->hash_len; + SilcUInt32 key_len = silc_cipher_get_key_len(conn->send_key); + SilcUInt32 hash_len = conn->hash->hash->hash_len; SILC_LOG_DEBUG(("Generating new %s session keys (no PFS)", send ? "sending" : "receiving")); @@ -755,10 +828,10 @@ silc_client_protocol_rekey_generate_pfs(SilcClient client, { SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data; SilcSKEKeyMaterial *keymat; - uint32 key_len = silc_cipher_get_key_len(conn->send_key); - uint32 hash_len = conn->hash->hash->hash_len; + SilcUInt32 key_len = silc_cipher_get_key_len(conn->send_key); + SilcUInt32 hash_len = conn->hash->hash->hash_len; unsigned char *tmpbuf; - uint32 klen; + SilcUInt32 klen; SILC_LOG_DEBUG(("Generating new %s session keys (with PFS)", send ? "sending" : "receiving")); @@ -837,31 +910,32 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) { /* Error in protocol */ protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, - 0, 300000); + silc_protocol_execute(protocol, client->schedule, 0, 300000); } - ctx->ske = silc_ske_alloc(); - ctx->ske->rng = client->rng; + ctx->ske = silc_ske_alloc(client->rng, client); ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop)); - silc_ske_get_group_by_number(conn->rekey->ske_group, + silc_ske_group_get_by_number(conn->rekey->ske_group, &ctx->ske->prop->group); - status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, - NULL, NULL, NULL, NULL); + silc_ske_set_callbacks(ctx->ske, + silc_client_protocol_rekey_send_packet, + NULL, NULL, NULL, silc_ske_check_version, + context); + + status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer); if (status != SILC_SKE_STATUS_OK) { SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)", status)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, client->schedule, 0, 300000); return; } /* Advance the protocol state */ protocol->state++; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); } else { /* * Do normal and simple re-key. @@ -895,24 +969,23 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) * Use Perfect Forward Secrecy, ie. negotiate the key material * using the SKE protocol. */ - ctx->ske = silc_ske_alloc(); - ctx->ske->rng = client->rng; + ctx->ske = silc_ske_alloc(client->rng, client); ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop)); - silc_ske_get_group_by_number(conn->rekey->ske_group, + silc_ske_group_get_by_number(conn->rekey->ske_group, &ctx->ske->prop->group); - status = - silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, - silc_client_protocol_rekey_send_packet, - context); - + silc_ske_set_callbacks(ctx->ske, + silc_client_protocol_rekey_send_packet, + NULL, NULL, NULL, silc_ske_check_version, + context); + + status = silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0); if (status != SILC_SKE_STATUS_OK) { SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)", status)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, client->schedule, 0, 300000); return; } @@ -951,19 +1024,15 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) * Send our KE packe to the initiator now that we've processed * the initiator's KE packet. */ - status = - silc_ske_responder_finish(ctx->ske, NULL, NULL, - SILC_SKE_PK_TYPE_SILC, - silc_client_protocol_rekey_send_packet, - context); + status = silc_ske_responder_finish(ctx->ske, NULL, NULL, + SILC_SKE_PK_TYPE_SILC); if (status != SILC_SKE_STATUS_OK) { SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)", status)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, client->schedule, 0, 300000); return; } } @@ -976,18 +1045,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) { /* Error in protocol */ protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 300000); + silc_protocol_execute(protocol, client->schedule, 0, 300000); } - status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer, - NULL, NULL, NULL, NULL); + status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer); if (status != SILC_SKE_STATUS_OK) { SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)", status)); protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, - protocol, fd, 0, 300000); + silc_protocol_execute(protocol, client->schedule, 0, 300000); return; } } @@ -1015,7 +1082,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) if (ctx->packet->type != SILC_PACKET_REKEY_DONE) { /* Error in protocol */ protocol->state = SILC_PROTOCOL_STATE_ERROR; - protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); } /* We received the REKEY_DONE packet and all packets after this is @@ -1024,7 +1091,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) /* Protocol has ended, call the final callback */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); break; @@ -1036,14 +1103,12 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) if (ctx->pfs == TRUE) { /* Send abort notification */ - silc_ske_abort(ctx->ske, ctx->ske->status, - silc_client_protocol_ke_send_packet, - context); + silc_ske_abort(ctx->ske, ctx->ske->status); } /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); break; @@ -1055,7 +1120,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) /* On error the final callback is always called. */ if (protocol->final_callback) - protocol->execute_final(client->timeout_queue, 0, protocol, fd); + silc_protocol_execute_final(protocol, client->schedule); else silc_protocol_free(protocol); break;