5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Client side of the protocols.
26 * Revision 1.1 2000/06/27 11:36:56 priikone
32 #include "clientincludes.h"
34 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
35 SILC_TASK_CALLBACK(silc_client_protocol_channel_auth);
36 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
38 /* SILC client protocol list */
39 const SilcProtocolObject silc_protocol_list[] =
41 { SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
42 silc_client_protocol_connection_auth },
43 { SILC_PROTOCOL_CLIENT_CHANNEL_AUTH,
44 silc_client_protocol_channel_auth },
45 { SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
46 silc_client_protocol_key_exchange },
48 { SILC_PROTOCOL_CLIENT_NONE, NULL },
52 * Key Exhange protocol functions
55 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
60 SilcProtocol protocol = (SilcProtocol)context;
61 SilcClientKEInternalContext *ctx =
62 (SilcClientKEInternalContext *)protocol->context;
63 SilcClient client = (SilcClient)ctx->client;
65 /* Send the packet immediately */
66 silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
67 packet->data, packet->len, TRUE);
71 static void silc_client_protocol_ke_phase1_cb(SilcSKE ske,
74 SilcProtocol protocol = (SilcProtocol)context;
75 SilcClientKEInternalContext *ctx =
76 (SilcClientKEInternalContext *)protocol->context;
77 SilcClient client = (SilcClient)ctx->client;
79 SILC_LOG_DEBUG(("Start"));
83 static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
86 SilcProtocol protocol = (SilcProtocol)context;
87 SilcClientKEInternalContext *ctx =
88 (SilcClientKEInternalContext *)protocol->context;
89 SilcClient client = (SilcClient)ctx->client;
91 SILC_LOG_DEBUG(("Start"));
95 /* Sets the negotiated key material into use for particular connection. */
97 static void silc_client_protocol_ke_set_keys(SilcSKE ske,
98 SilcSocketConnection sock,
99 SilcSKEKeyMaterial *keymat,
104 SilcClientWindow win = (SilcClientWindow)sock->user_data;
107 SILC_LOG_DEBUG(("Setting new keys into use"));
109 /* Allocate cipher to be used in the communication */
110 silc_cipher_alloc(cipher->cipher->name, &win->send_key);
111 silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
113 win->send_key->cipher->set_key(win->send_key->context,
114 keymat->send_enc_key,
115 keymat->enc_key_len);
116 win->send_key->set_iv(win->send_key, keymat->send_iv);
117 win->receive_key->cipher->set_key(win->receive_key->context,
118 keymat->receive_enc_key,
119 keymat->enc_key_len);
120 win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
122 /* Allocate PKCS to be used */
124 /* XXX Do we ever need to allocate PKCS for the connection??
125 If yes, we need to change KE protocol to get the initiators
127 silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
128 silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data,
129 ske->ke2_payload->pk_len);
132 /* Save HMAC key to be used in the communication. */
133 silc_hash_alloc(hash->hash->name, &nhash);
134 silc_hmac_alloc(nhash, &win->hmac);
135 win->hmac_key_len = keymat->hmac_key_len;
136 win->hmac_key = silc_calloc(win->hmac_key_len,
137 sizeof(unsigned char));
138 memcpy(win->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
142 /* Performs key exchange protocol. This is used for both initiator
143 and responder key exchange. This may be called recursively. */
145 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
147 SilcProtocol protocol = (SilcProtocol)context;
148 SilcClientKEInternalContext *ctx =
149 (SilcClientKEInternalContext *)protocol->context;
150 SilcClient client = (SilcClient)ctx->client;
151 SilcSKEStatus status;
153 SILC_LOG_DEBUG(("Start"));
155 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
156 protocol->state = SILC_PROTOCOL_STATE_START;
158 switch(protocol->state) {
159 case SILC_PROTOCOL_STATE_START:
166 /* Allocate Key Exchange object */
167 ske = silc_ske_alloc();
170 if (ctx->responder == TRUE) {
172 SilcBuffer start_payload;
175 /* Start the key exchange by processing the received security
176 properties packet from initiator. */
177 status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
179 silc_client_protocol_ke_send_packet,
183 SilcSKEStartPayload *start_payload;
185 /* Assemble security properties. */
186 silc_ske_assemble_security_properties(ske, &start_payload);
188 /* Start the key exchange by sending our security properties
189 to the remote end. */
190 status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
192 silc_client_protocol_ke_send_packet,
196 if (status != SILC_SKE_STATUS_OK) {
204 /* Advance the state of the protocol. */
213 if (ctx->responder == TRUE) {
216 silc_ske_responder_phase_1(ctx->ske,
217 ctx->ske->start_payload,
218 silc_server_protocol_ke_send_packet,
222 /* Call Phase-1 function. This processes the Key Exchange Start
223 paylaod reply we just got from the responder. The callback
224 function will receive the processed payload where we will
227 silc_ske_initiator_phase_1(ctx->ske,
229 silc_client_protocol_ke_phase1_cb,
238 /* Advance the state of the protocol and call the next state. */
240 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
248 if (ctx->responder == TRUE) {
251 silc_ske_responder_phase_2(ctx->ske,
252 ctx->ske->start_payload,
253 silc_server_protocol_ke_send_packet,
257 /* Call the Phase-2 function. This creates Diffie Hellman
258 key exchange parameters and sends our public part inside
259 Key Exhange 1 Payload to the responder. */
261 silc_ske_initiator_phase_2(ctx->ske,
262 silc_client_protocol_ke_send_packet,
271 /* Advance the state of the protocol. */
280 if (ctx->responder == TRUE) {
283 silc_ske_responder_phase_2(ctx->ske,
284 ctx->ske->start_payload,
285 silc_server_protocol_ke_send_packet,
289 /* Finish the protocol. This verifies the Key Exchange 2 payload
290 sent by responder. */
292 silc_ske_initiator_finish(ctx->ske,
294 silc_client_protocol_ke_finish_cb,
303 /* Send Ok to the other end. We will end the protocol as server
304 sends Ok to us when we will take the new keys into use. */
305 silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
307 /* End the protocol on the next round */
308 protocol->state = SILC_PROTOCOL_STATE_END;
311 case SILC_PROTOCOL_STATE_END:
316 SilcSKEKeyMaterial *keymat;
318 /* Process the key material */
319 keymat = silc_calloc(1, sizeof(*keymat));
320 silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
322 /* Take the negotiated keys into use. */
323 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
324 ctx->ske->prop->cipher,
325 ctx->ske->prop->pkcs,
326 ctx->ske->prop->hash);
328 /* Protocol has ended, call the final callback */
329 if (protocol->final_callback)
330 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
332 silc_protocol_free(protocol);
335 case SILC_PROTOCOL_STATE_ERROR:
337 /* On error the final callback is always called. */
338 /* protocol->final_callback(pptr, context);*/
340 case SILC_PROTOCOL_STATE_UNKNOWN:
346 * Connection Authentication protocol functions
349 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
351 SilcProtocol protocol = (SilcProtocol)context;
352 SilcClientConnAuthInternalContext *ctx =
353 (SilcClientConnAuthInternalContext *)protocol->context;
354 SilcClient client = (SilcClient)ctx->client;
356 SILC_LOG_DEBUG(("Start"));
358 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
359 protocol->state = SILC_PROTOCOL_STATE_START;
361 switch(protocol->state) {
362 case SILC_PROTOCOL_STATE_START:
365 * Start protocol. We send authentication data to the server
366 * to be authenticated.
370 unsigned char *auth_data = NULL;
371 unsigned int auth_data_len = 0;
373 switch(ctx->auth_meth) {
374 case SILC_PROTOCOL_CONN_AUTH_NONE:
375 /* No authentication required */
378 case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
379 /* Password authentication */
380 if (ctx->auth_data && ctx->auth_data_len) {
381 auth_data = ctx->auth_data;
382 auth_data_len = ctx->auth_data_len;
386 silc_say(client, "Password authentication required by server %s",
387 ctx->sock->hostname);
388 auth_data = silc_client_ask_passphrase(client);
389 auth_data_len = strlen(auth_data);
392 case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
399 payload_len = 4 + auth_data_len;
400 packet = silc_buffer_alloc(payload_len);
401 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
402 silc_buffer_format(packet,
403 SILC_STR_UI_SHORT(payload_len),
404 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
405 SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
408 /* Send the packet to server */
409 silc_client_packet_send(client, ctx->sock,
410 SILC_PACKET_CONNECTION_AUTH,
412 packet->data, packet->len, TRUE);
415 memset(auth_data, 0, auth_data_len);
416 silc_free(auth_data);
418 silc_buffer_free(packet);
420 /* Next state is end of protocol */
421 protocol->state = SILC_PROTOCOL_STATE_END;
425 case SILC_PROTOCOL_STATE_END:
428 * End protocol. Nothing special to be done here.
431 /* Protocol has ended, call the final callback */
432 if (protocol->final_callback)
433 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
435 silc_protocol_free(protocol);
439 case SILC_PROTOCOL_STATE_ERROR:
445 /* Error in protocol. Send FAILURE packet. Although I don't think
446 this could ever happen on client side. */
447 silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
448 NULL, 0, NULL, NULL, NULL, 0, TRUE);
450 /* On error the final callback is always called. */
451 if (protocol->final_callback)
452 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
454 silc_protocol_free(protocol);
457 case SILC_PROTOCOL_STATE_UNKNOWN:
462 SILC_TASK_CALLBACK(silc_client_protocol_channel_auth)