Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 1997 - 2000 Pekka Riikonen
+ Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
/* $Id$ */
#include "clientlibincludes.h"
+#include "client_internal.h"
SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
/* Function that is called when SKE protocol sends packets to network. */
-static void silc_client_protocol_ke_send_packet(SilcSKE ske,
- SilcBuffer packet,
- SilcPacketType type,
- void *context)
+void silc_client_protocol_ke_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
{
SilcProtocol protocol = (SilcProtocol)context;
SilcClientKEInternalContext *ctx =
/* Callback that is called when we have received KE2 payload from
responder. We try to verify the public key now. */
-static SilcSKEStatus
-silc_client_protocol_ke_verify_key(SilcSKE ske,
- unsigned char *pk_data,
- unsigned int pk_len,
- SilcSKEPKType pk_type,
- void *context)
+SilcSKEStatus silc_client_protocol_ke_verify_key(SilcSKE ske,
+ unsigned char *pk_data,
+ unsigned int pk_len,
+ SilcSKEPKType pk_type,
+ void *context)
{
SilcProtocol protocol = (SilcProtocol)context;
SilcClientKEInternalContext *ctx =
SILC_LOG_DEBUG(("Start"));
- /* Verify server key from user. */
- if (!client->ops->verify_server_key(client, ctx->sock->user_data,
+ /* 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;
/* Sets the negotiated key material into use for particular connection. */
-static void silc_client_protocol_ke_set_keys(SilcSKE ske,
- SilcSocketConnection sock,
- SilcSKEKeyMaterial *keymat,
- SilcCipher cipher,
- SilcPKCS pkcs,
- SilcHash hash)
+void silc_client_protocol_ke_set_keys(SilcSKE ske,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat,
+ SilcCipher cipher,
+ SilcPKCS pkcs,
+ SilcHash hash,
+ SilcHmac hmac)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- SilcHash nhash;
SILC_LOG_DEBUG(("Setting new keys into use"));
#endif
/* Save HMAC key to be used in the communication. */
- silc_hash_alloc(hash->hash->name, &nhash);
- silc_hmac_alloc(nhash, &conn->hmac);
+ silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac);
silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
+
+ /* Save the HASH function */
+ silc_hash_alloc(hash->hash->name, &conn->hash);
}
-/* XXX TODO */
+/* Checks the version string of the server. */
SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
unsigned int len)
{
- return SILC_SKE_STATUS_OK;
+ SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data;
+ SilcClient client = (SilcClient)ske->user_data;
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+
+ /* Check for initial version string */
+ if (!strstr(version, "SILC-1.0-"))
+ status = SILC_SKE_STATUS_BAD_VERSION;
+
+ /* Check software version */
+
+ if (len < strlen(silc_version_string))
+ status = SILC_SKE_STATUS_BAD_VERSION;
+
+ /* XXX for now there is no other tests due to the abnormal version
+ string that is used */
+
+ if (status != SILC_SKE_STATUS_OK)
+ client->ops->say(client, conn,
+ "We don't support server version `%s'", version);
+
+ return status;
}
/* Performs key exchange protocol. This is used for both initiator
ske = silc_ske_alloc();
ctx->ske = ske;
ske->rng = client->rng;
+ ske->user_data = (void *)client;
if (ctx->responder == TRUE) {
-#if 0
- SilcBuffer start_payload;
-
-
/* Start the key exchange by processing the received security
properties packet from initiator. */
status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
- start_payload,
- silc_client_protocol_ke_send_packet,
- context);
-#endif
+ silc_version_string,
+ ctx->packet->buffer, TRUE,
+ NULL, NULL);
} else {
SilcSKEStartPayload *start_payload;
to the remote end. */
status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
start_payload,
- silc_client_protocol_ke_send_packet,
+ ctx->send_packet,
context);
}
return;
}
- /* Advance the state of the protocol. */
+ /* 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 2:
* Phase 1
*/
if (ctx->responder == TRUE) {
-#if 0
+ /* Sends the selected security properties to the initiator. */
status =
silc_ske_responder_phase_1(ctx->ske,
ctx->ske->start_payload,
- silc_server_protocol_ke_send_packet,
+ ctx->send_packet,
context);
-#endif
} 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, NULL, NULL);
+ status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer,
+ NULL, NULL);
}
if (status != SILC_SKE_STATUS_OK) {
return;
}
- /* Advance the state of the protocol and call the next state. */
+ /* Advance protocol state and call next state if we are initiator */
protocol->state++;
- protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+ if (ctx->responder == FALSE)
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000);
}
break;
case 3:
* Phase 2
*/
if (ctx->responder == TRUE) {
-#if 0
- status =
- silc_ske_responder_phase_2(ctx->ske,
- ctx->ske->start_payload,
- silc_server_protocol_ke_send_packet,
- context);
-#endif
+ /* 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);
} else {
/* Call the Phase-2 function. This creates Diffie Hellman
key exchange parameters and sends our public part inside
Key Exhange 1 Payload to the responder. */
- status =
- silc_ske_initiator_phase_2(ctx->ske,
- client->public_key,
- silc_client_protocol_ke_send_packet,
- context);
+ status = silc_ske_initiator_phase_2(ctx->ske,
+ client->public_key,
+ client->private_key,
+ ctx->send_packet,
+ context);
}
if (status != SILC_SKE_STATUS_OK) {
return;
}
- /* Advance the state of the protocol. */
+ /* 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:
* Finish protocol
*/
if (ctx->responder == TRUE) {
- status = 0;
-#if 0
+ /* This creates the key exchange material and sends our
+ public parts to the initiator inside Key Exchange 2 Payload. */
status =
- silc_ske_responder_phase_2(ctx->ske,
- ctx->ske->start_payload,
- silc_server_protocol_ke_send_packet,
- context);
-#endif
+ silc_ske_responder_finish(ctx->ske,
+ client->public_key, client->private_key,
+ SILC_SKE_PK_TYPE_SILC,
+ ctx->send_packet,
+ context);
+ status = 0;
} else {
/* Finish the protocol. This verifies the Key Exchange 2 payload
sent by responder. */
- status = silc_ske_initiator_finish(ctx->ske, ctx->packet,
- silc_client_protocol_ke_verify_key,
- context, NULL, NULL);
+ status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
+ ctx->verify, context, NULL, NULL);
}
if (status != SILC_SKE_STATUS_OK) {
/* 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. */
- silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
+ 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;
* End protocol
*/
SilcSKEKeyMaterial *keymat;
+ int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher);
+ int hash_len = ctx->ske->prop->hash->hash->hash_len;
/* Process the key material */
keymat = silc_calloc(1, sizeof(*keymat));
- silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
+ status = silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len,
+ keymat);
+ if (status != SILC_SKE_STATUS_OK) {
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 300000);
+ silc_ske_free_key_material(keymat);
+ return;
+ }
+ ctx->keymat = keymat;
- /* Take the negotiated keys into use. */
- silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
- ctx->ske->prop->cipher,
- ctx->ske->prop->pkcs,
- ctx->ske->prop->hash);
+ /* 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);
+
+ /* 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);
/* Protocol has ended, call the final callback */
if (protocol->final_callback)
/* Send abort notification */
silc_ske_abort(ctx->ske, ctx->ske->status,
- silc_client_protocol_ke_send_packet,
- context);
+ ctx->send_packet, context);
/* On error the final callback is always called. */
if (protocol->final_callback)
* Received failure from remote.
*/
+ /* 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);
+
/* On error the final callback is always called. */
if (protocol->final_callback)
protocol->execute_final(client->timeout_queue, 0, protocol, fd);
unsigned int auth_data_len = 0;
switch(ctx->auth_meth) {
- case SILC_PROTOCOL_CONN_AUTH_NONE:
+ case SILC_AUTH_NONE:
/* No authentication required */
break;
- case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+ case SILC_AUTH_PASSWORD:
/* Password authentication */
if (ctx->auth_data && ctx->auth_data_len) {
auth_data = ctx->auth_data;
auth_data_len = strlen(auth_data);
break;
- case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+ case SILC_AUTH_PUBLIC_KEY:
/* XXX */
break;
}
*/
unsigned char error[4];
- SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
+ SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
/* Error in protocol. Send FAILURE packet. Although I don't think
this could ever happen on client side. */