5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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.
25 #include "clientlibincludes.h"
27 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
28 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
30 extern char *silc_version_string;
33 * Key Exhange protocol functions
36 /* Function that is called when SKE protocol sends packets to network. */
38 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
43 SilcProtocol protocol = (SilcProtocol)context;
44 SilcClientKEInternalContext *ctx =
45 (SilcClientKEInternalContext *)protocol->context;
46 SilcClient client = (SilcClient)ctx->client;
48 /* Send the packet immediately */
49 silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
50 packet->data, packet->len, TRUE);
54 /* Callback that is called when we have received KE2 payload from
55 responder. We try to verify the public key now. */
58 silc_client_protocol_ke_verify_key(SilcSKE ske,
59 unsigned char *pk_data,
61 SilcSKEPKType pk_type,
64 SilcProtocol protocol = (SilcProtocol)context;
65 SilcClientKEInternalContext *ctx =
66 (SilcClientKEInternalContext *)protocol->context;
67 SilcClient client = (SilcClient)ctx->client;
69 SILC_LOG_DEBUG(("Start"));
71 /* Verify server key from user. */
72 if (!client->ops->verify_server_key(client, ctx->sock->user_data,
73 pk_data, pk_len, pk_type))
74 return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
76 return SILC_SKE_STATUS_OK;
79 /* Sets the negotiated key material into use for particular connection. */
81 static void silc_client_protocol_ke_set_keys(SilcSKE ske,
82 SilcSocketConnection sock,
83 SilcSKEKeyMaterial *keymat,
88 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
91 SILC_LOG_DEBUG(("Setting new keys into use"));
93 /* Allocate cipher to be used in the communication */
94 silc_cipher_alloc(cipher->cipher->name, &conn->send_key);
95 silc_cipher_alloc(cipher->cipher->name, &conn->receive_key);
97 conn->send_key->cipher->set_key(conn->send_key->context,
100 conn->send_key->set_iv(conn->send_key, keymat->send_iv);
101 conn->receive_key->cipher->set_key(conn->receive_key->context,
102 keymat->receive_enc_key,
103 keymat->enc_key_len);
104 conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv);
106 /* Allocate PKCS to be used */
108 /* XXX Do we ever need to allocate PKCS for the connection??
109 If yes, we need to change KE protocol to get the initiators
111 silc_pkcs_alloc(pkcs->pkcs->name, &conn->public_Key);
112 silc_pkcs_set_public_key(conn->public_key, ske->ke2_payload->pk_data,
113 ske->ke2_payload->pk_len);
116 /* Save HMAC key to be used in the communication. */
117 silc_hash_alloc(hash->hash->name, &nhash);
118 silc_hmac_alloc(nhash, &conn->hmac);
119 silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
122 /* Checks the version string of the server. */
124 SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
127 SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data;
128 SilcClient client = (SilcClient)ske->user_data;
129 SilcSKEStatus status = SILC_SKE_STATUS_OK;
131 /* Check for initial version string */
132 if (!strstr(version, "SILC-1.0-"))
133 status = SILC_SKE_STATUS_BAD_VERSION;
135 /* Check software version */
137 if (len < strlen(silc_version_string))
138 status = SILC_SKE_STATUS_BAD_VERSION;
140 /* XXX for now there is no other tests due to the abnormal version
141 string that is used */
143 if (status != SILC_SKE_STATUS_OK)
144 client->ops->say(client, conn,
145 "We don't support server version `%s'", version);
150 /* Performs key exchange protocol. This is used for both initiator
151 and responder key exchange. This may be called recursively. */
153 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
155 SilcProtocol protocol = (SilcProtocol)context;
156 SilcClientKEInternalContext *ctx =
157 (SilcClientKEInternalContext *)protocol->context;
158 SilcClient client = (SilcClient)ctx->client;
159 SilcClientConnection conn = ctx->sock->user_data;
160 SilcSKEStatus status = 0;
162 SILC_LOG_DEBUG(("Start"));
164 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
165 protocol->state = SILC_PROTOCOL_STATE_START;
167 switch(protocol->state) {
168 case SILC_PROTOCOL_STATE_START:
175 /* Allocate Key Exchange object */
176 ske = silc_ske_alloc();
178 ske->rng = client->rng;
179 ske->user_data = (void *)client;
181 if (ctx->responder == TRUE) {
183 SilcBuffer start_payload;
186 /* Start the key exchange by processing the received security
187 properties packet from initiator. */
188 status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
190 silc_client_protocol_ke_send_packet,
194 SilcSKEStartPayload *start_payload;
196 /* Assemble security properties. */
197 silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE,
201 /* Start the key exchange by sending our security properties
202 to the remote end. */
203 status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
205 silc_client_protocol_ke_send_packet,
209 if (status != SILC_SKE_STATUS_OK) {
210 SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
212 SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
215 protocol->state = SILC_PROTOCOL_STATE_ERROR;
216 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
220 /* Advance the state of the protocol. */
229 if (ctx->responder == TRUE) {
232 silc_ske_responder_phase_1(ctx->ske,
233 ctx->ske->start_payload,
234 silc_server_protocol_ke_send_packet,
238 /* Call Phase-1 function. This processes the Key Exchange Start
239 paylaod reply we just got from the responder. The callback
240 function will receive the processed payload where we will
242 status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer,
246 if (status != SILC_SKE_STATUS_OK) {
247 SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
249 SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
252 protocol->state = SILC_PROTOCOL_STATE_ERROR;
253 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
257 /* Advance the state of the protocol and call the next state. */
259 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
267 if (ctx->responder == TRUE) {
270 silc_ske_responder_phase_2(ctx->ske,
271 ctx->ske->start_payload,
272 silc_server_protocol_ke_send_packet,
276 /* Call the Phase-2 function. This creates Diffie Hellman
277 key exchange parameters and sends our public part inside
278 Key Exhange 1 Payload to the responder. */
280 silc_ske_initiator_phase_2(ctx->ske,
282 silc_client_protocol_ke_send_packet,
286 if (status != SILC_SKE_STATUS_OK) {
287 SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
289 SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
292 protocol->state = SILC_PROTOCOL_STATE_ERROR;
293 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
297 /* Advance the state of the protocol. */
306 if (ctx->responder == TRUE) {
310 silc_ske_responder_phase_2(ctx->ske,
311 ctx->ske->start_payload,
312 silc_server_protocol_ke_send_packet,
316 /* Finish the protocol. This verifies the Key Exchange 2 payload
317 sent by responder. */
318 status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
319 silc_client_protocol_ke_verify_key,
320 context, NULL, NULL);
323 if (status != SILC_SKE_STATUS_OK) {
325 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
326 client->ops->say(client, conn,
327 "Received unsupported server %s public key",
328 ctx->sock->hostname);
330 client->ops->say(client, conn,
331 "Error during key exchange protocol with server %s",
332 ctx->sock->hostname);
334 protocol->state = SILC_PROTOCOL_STATE_ERROR;
335 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
339 /* Send Ok to the other end. We will end the protocol as server
340 sends Ok to us when we will take the new keys into use. */
341 silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
343 /* End the protocol on the next round */
344 protocol->state = SILC_PROTOCOL_STATE_END;
348 case SILC_PROTOCOL_STATE_END:
353 SilcSKEKeyMaterial *keymat;
354 int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher, NULL);
355 int hash_len = ctx->ske->prop->hash->hash->hash_len;
357 /* Process the key material */
358 keymat = silc_calloc(1, sizeof(*keymat));
359 silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len,
362 /* Take the negotiated keys into use. */
363 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
364 ctx->ske->prop->cipher,
365 ctx->ske->prop->pkcs,
366 ctx->ske->prop->hash);
368 /* Protocol has ended, call the final callback */
369 if (protocol->final_callback)
370 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
372 silc_protocol_free(protocol);
376 case SILC_PROTOCOL_STATE_ERROR:
378 * Error during protocol
381 /* Send abort notification */
382 silc_ske_abort(ctx->ske, ctx->ske->status,
383 silc_client_protocol_ke_send_packet,
386 /* On error the final callback is always called. */
387 if (protocol->final_callback)
388 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
390 silc_protocol_free(protocol);
393 case SILC_PROTOCOL_STATE_FAILURE:
395 * Received failure from remote.
398 /* On error the final callback is always called. */
399 if (protocol->final_callback)
400 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
402 silc_protocol_free(protocol);
404 case SILC_PROTOCOL_STATE_UNKNOWN:
410 * Connection Authentication protocol functions
413 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
415 SilcProtocol protocol = (SilcProtocol)context;
416 SilcClientConnAuthInternalContext *ctx =
417 (SilcClientConnAuthInternalContext *)protocol->context;
418 SilcClient client = (SilcClient)ctx->client;
419 SilcClientConnection conn = ctx->sock->user_data;
421 SILC_LOG_DEBUG(("Start"));
423 if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
424 protocol->state = SILC_PROTOCOL_STATE_START;
426 switch(protocol->state) {
427 case SILC_PROTOCOL_STATE_START:
430 * Start protocol. We send authentication data to the server
431 * to be authenticated.
435 unsigned char *auth_data = NULL;
436 unsigned int auth_data_len = 0;
438 switch(ctx->auth_meth) {
440 /* No authentication required */
443 case SILC_AUTH_PASSWORD:
444 /* Password authentication */
445 if (ctx->auth_data && ctx->auth_data_len) {
446 auth_data = ctx->auth_data;
447 auth_data_len = ctx->auth_data_len;
451 client->ops->say(client, conn,
452 "Password authentication required by server %s",
453 ctx->sock->hostname);
454 auth_data = client->ops->ask_passphrase(client, conn);
455 auth_data_len = strlen(auth_data);
458 case SILC_AUTH_PUBLIC_KEY:
463 payload_len = 4 + auth_data_len;
464 packet = silc_buffer_alloc(payload_len);
465 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
466 silc_buffer_format(packet,
467 SILC_STR_UI_SHORT(payload_len),
468 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
469 SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
472 /* Send the packet to server */
473 silc_client_packet_send(client, ctx->sock,
474 SILC_PACKET_CONNECTION_AUTH,
476 packet->data, packet->len, TRUE);
479 memset(auth_data, 0, auth_data_len);
480 silc_free(auth_data);
482 silc_buffer_free(packet);
484 /* Next state is end of protocol */
485 protocol->state = SILC_PROTOCOL_STATE_END;
489 case SILC_PROTOCOL_STATE_END:
492 * End protocol. Nothing special to be done here.
495 /* Protocol has ended, call the final callback */
496 if (protocol->final_callback)
497 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
499 silc_protocol_free(protocol);
503 case SILC_PROTOCOL_STATE_ERROR:
506 * Error. Send notify to remote.
508 unsigned char error[4];
510 SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
512 /* Error in protocol. Send FAILURE packet. Although I don't think
513 this could ever happen on client side. */
514 silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
515 NULL, 0, NULL, NULL, error, 4, TRUE);
517 /* On error the final callback is always called. */
518 if (protocol->final_callback)
519 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
521 silc_protocol_free(protocol);
524 case SILC_PROTOCOL_STATE_FAILURE:
526 * Received failure from remote.
529 /* On error the final callback is always called. */
530 if (protocol->final_callback)
531 protocol->execute_final(client->timeout_queue, 0, protocol, fd);
533 silc_protocol_free(protocol);
536 case SILC_PROTOCOL_STATE_UNKNOWN:
541 /* Registers protocols used in client */
543 void silc_client_protocols_register(void)
545 silc_protocol_register(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
546 silc_client_protocol_connection_auth);
547 silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
548 silc_client_protocol_key_exchange);
551 /* Unregisters protocols */
553 void silc_client_protocols_unregister(void)
555 silc_protocol_unregister(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
556 silc_client_protocol_connection_auth);
557 silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
558 silc_client_protocol_key_exchange);