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.8 2000/07/20 10:17:25 priikone
27 * Added dynamic protocol registering/unregistering support. The
28 * patch was provided by cras.
30 * Revision 1.7 2000/07/19 07:07:47 priikone
31 * Added version detection support to SKE.
33 * Revision 1.6 2000/07/14 06:12:29 priikone
34 * Put the HMAC keys into the HMAC object instead on having them
35 * saved elsewhere; we can use now silc_hmac_make instead of
36 * silc_hmac_make_with_key.
38 * Revision 1.5 2000/07/07 11:36:09 priikone
39 * Inform user when received unsupported public key from server.
41 * Revision 1.4 2000/07/07 06:53:45 priikone
42 * Added support for server public key verification.
44 * Revision 1.3 2000/07/06 07:14:16 priikone
45 * Deprecated old `channel_auth' protocol.
47 * Revision 1.2 2000/07/05 06:12:05 priikone
48 * Global cosmetic changes.
50 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
51 * Imported from internal CVS/Added Log headers.
56 #include "clientincludes.h"
58 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
59 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
61 extern char *silc_version_string;
64 * Key Exhange protocol functions
67 /* Function that is called when SKE protocol sends packets to network. */
69 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
74 SilcProtocol protocol = (SilcProtocol)context;
75 SilcClientKEInternalContext *ctx =
76 (SilcClientKEInternalContext *)protocol->context;
77 SilcClient client = (SilcClient)ctx->client;
79 /* Send the packet immediately */
80 silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
81 packet->data, packet->len, TRUE);
85 /* Callback that is called when we have received KE2 payload from
86 responder. We try to verify the public key now. */
89 silc_client_protocol_ke_verify_key(SilcSKE ske,
90 unsigned char *pk_data,
92 SilcSKEPKType pk_type,
95 SilcProtocol protocol = (SilcProtocol)context;
96 SilcClientKEInternalContext *ctx =
97 (SilcClientKEInternalContext *)protocol->context;
98 SilcClient client = (SilcClient)ctx->client;
100 SILC_LOG_DEBUG(("Start"));
102 if (!silc_client_verify_server_key(client, ctx->sock,
103 pk_data, pk_len, pk_type))
104 return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
106 return SILC_SKE_STATUS_OK;
109 /* Sets the negotiated key material into use for particular connection. */
111 static void silc_client_protocol_ke_set_keys(SilcSKE ske,
112 SilcSocketConnection sock,
113 SilcSKEKeyMaterial *keymat,
118 SilcClientWindow win = (SilcClientWindow)sock->user_data;
121 SILC_LOG_DEBUG(("Setting new keys into use"));
123 /* Allocate cipher to be used in the communication */
124 silc_cipher_alloc(cipher->cipher->name, &win->send_key);
125 silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
127 win->send_key->cipher->set_key(win->send_key->context,
128 keymat->send_enc_key,
129 keymat->enc_key_len);
130 win->send_key->set_iv(win->send_key, keymat->send_iv);
131 win->receive_key->cipher->set_key(win->receive_key->context,
132 keymat->receive_enc_key,
133 keymat->enc_key_len);
134 win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
136 /* Allocate PKCS to be used */
138 /* XXX Do we ever need to allocate PKCS for the connection??
139 If yes, we need to change KE protocol to get the initiators
141 silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
142 silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data,
143 ske->ke2_payload->pk_len);
146 /* Save HMAC key to be used in the communication. */
147 silc_hash_alloc(hash->hash->name, &nhash);
148 silc_hmac_alloc(nhash, &win->hmac);
149 silc_hmac_set_key(win->hmac, keymat->hmac_key, keymat->hmac_key_len);
152 /* Performs key exchange protocol. This is used for both initiator
153 and responder key exchange. This may be called recursively. */
155 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
157 SilcProtocol protocol = (SilcProtocol)context;
158 SilcClientKEInternalContext *ctx =
159 (SilcClientKEInternalContext *)protocol->context;
160 SilcClient client = (SilcClient)ctx->client;
161 SilcSKEStatus status;
163 SILC_LOG_DEBUG(("Start"));
165 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
166 protocol->state = SILC_PROTOCOL_STATE_START;
168 switch(protocol->state) {
169 case SILC_PROTOCOL_STATE_START:
176 /* Allocate Key Exchange object */
177 ske = silc_ske_alloc();
180 if (ctx->responder == TRUE) {
182 SilcBuffer start_payload;
185 /* Start the key exchange by processing the received security
186 properties packet from initiator. */
187 status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
189 silc_client_protocol_ke_send_packet,
193 SilcSKEStartPayload *start_payload;
195 /* Assemble security properties. */
196 silc_ske_assemble_security_properties(ske, silc_version_string,
199 /* Start the key exchange by sending our security properties
200 to the remote end. */
201 status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
203 silc_client_protocol_ke_send_packet,
207 if (status != SILC_SKE_STATUS_OK) {
215 /* Advance the state of the protocol. */
224 if (ctx->responder == TRUE) {
227 silc_ske_responder_phase_1(ctx->ske,
228 ctx->ske->start_payload,
229 silc_server_protocol_ke_send_packet,
233 /* Call Phase-1 function. This processes the Key Exchange Start
234 paylaod reply we just got from the responder. The callback
235 function will receive the processed payload where we will
237 status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet, NULL, NULL);
245 /* Advance the state of the protocol and call the next state. */
247 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
255 if (ctx->responder == TRUE) {
258 silc_ske_responder_phase_2(ctx->ske,
259 ctx->ske->start_payload,
260 silc_server_protocol_ke_send_packet,
264 /* Call the Phase-2 function. This creates Diffie Hellman
265 key exchange parameters and sends our public part inside
266 Key Exhange 1 Payload to the responder. */
268 silc_ske_initiator_phase_2(ctx->ske,
270 silc_client_protocol_ke_send_packet,
279 /* Advance the state of the protocol. */
288 if (ctx->responder == TRUE) {
292 silc_ske_responder_phase_2(ctx->ske,
293 ctx->ske->start_payload,
294 silc_server_protocol_ke_send_packet,
298 /* Finish the protocol. This verifies the Key Exchange 2 payload
299 sent by responder. */
300 status = silc_ske_initiator_finish(ctx->ske, ctx->packet,
301 silc_client_protocol_ke_verify_key,
302 context, NULL, NULL);
305 if (status != SILC_SKE_STATUS_OK) {
307 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
308 silc_say(client, "Received unsupported server %s public key",
309 ctx->sock->hostname);
311 silc_say(client, "Error during key exchange protocol with server %s",
312 ctx->sock->hostname);
314 protocol->state = SILC_PROTOCOL_STATE_ERROR;
315 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
319 /* Send Ok to the other end. We will end the protocol as server
320 sends Ok to us when we will take the new keys into use. */
321 silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
323 /* End the protocol on the next round */
324 protocol->state = SILC_PROTOCOL_STATE_END;
327 case SILC_PROTOCOL_STATE_END:
332 SilcSKEKeyMaterial *keymat;
334 /* Process the key material */
335 keymat = silc_calloc(1, sizeof(*keymat));
336 silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
338 /* Take the negotiated keys into use. */
339 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
340 ctx->ske->prop->cipher,
341 ctx->ske->prop->pkcs,
342 ctx->ske->prop->hash);
344 /* Protocol has ended, call the final callback */
345 if (protocol->final_callback)
346 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
348 silc_protocol_free(protocol);
351 case SILC_PROTOCOL_STATE_ERROR:
353 /* On error the final callback is always called. */
354 if (protocol->final_callback)
355 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
357 silc_protocol_free(protocol);
359 case SILC_PROTOCOL_STATE_UNKNOWN:
365 * Connection Authentication protocol functions
368 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
370 SilcProtocol protocol = (SilcProtocol)context;
371 SilcClientConnAuthInternalContext *ctx =
372 (SilcClientConnAuthInternalContext *)protocol->context;
373 SilcClient client = (SilcClient)ctx->client;
375 SILC_LOG_DEBUG(("Start"));
377 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
378 protocol->state = SILC_PROTOCOL_STATE_START;
380 switch(protocol->state) {
381 case SILC_PROTOCOL_STATE_START:
384 * Start protocol. We send authentication data to the server
385 * to be authenticated.
389 unsigned char *auth_data = NULL;
390 unsigned int auth_data_len = 0;
392 switch(ctx->auth_meth) {
393 case SILC_PROTOCOL_CONN_AUTH_NONE:
394 /* No authentication required */
397 case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
398 /* Password authentication */
399 if (ctx->auth_data && ctx->auth_data_len) {
400 auth_data = ctx->auth_data;
401 auth_data_len = ctx->auth_data_len;
405 silc_say(client, "Password authentication required by server %s",
406 ctx->sock->hostname);
407 auth_data = silc_client_ask_passphrase(client);
408 auth_data_len = strlen(auth_data);
411 case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
416 payload_len = 4 + auth_data_len;
417 packet = silc_buffer_alloc(payload_len);
418 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
419 silc_buffer_format(packet,
420 SILC_STR_UI_SHORT(payload_len),
421 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
422 SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
425 /* Send the packet to server */
426 silc_client_packet_send(client, ctx->sock,
427 SILC_PACKET_CONNECTION_AUTH,
429 packet->data, packet->len, TRUE);
432 memset(auth_data, 0, auth_data_len);
433 silc_free(auth_data);
435 silc_buffer_free(packet);
437 /* Next state is end of protocol */
438 protocol->state = SILC_PROTOCOL_STATE_END;
442 case SILC_PROTOCOL_STATE_END:
445 * End protocol. Nothing special to be done here.
448 /* Protocol has ended, call the final callback */
449 if (protocol->final_callback)
450 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
452 silc_protocol_free(protocol);
456 case SILC_PROTOCOL_STATE_ERROR:
462 /* Error in protocol. Send FAILURE packet. Although I don't think
463 this could ever happen on client side. */
464 silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
465 NULL, 0, NULL, NULL, NULL, 0, TRUE);
467 /* On error the final callback is always called. */
468 if (protocol->final_callback)
469 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
471 silc_protocol_free(protocol);
474 case SILC_PROTOCOL_STATE_UNKNOWN:
479 /* Registers protocols used in client */
481 void silc_client_protocols_register(void)
483 silc_protocol_register(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
484 silc_client_protocol_connection_auth);
485 silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
486 silc_client_protocol_key_exchange);
489 /* Unregisters protocols */
491 void silc_client_protocols_unregister(void)
493 silc_protocol_unregister(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
494 silc_client_protocol_connection_auth);
495 silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
496 silc_client_protocol_key_exchange);