Global cosmetic changes.
[silc.git] / apps / silc / protocol.c
1 /*
2
3   protocol.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /*
21  * Client side of the protocols.
22  */
23 /*
24  * $Id$
25  * $Log$
26  * Revision 1.2  2000/07/05 06:12:05  priikone
27  *      Global cosmetic changes.
28  *
29  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
30  *      Imported from internal CVS/Added Log headers.
31  *
32  *
33  */
34
35 #include "clientincludes.h"
36
37 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
38 SILC_TASK_CALLBACK(silc_client_protocol_channel_auth);
39 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
40
41 /* SILC client protocol list */
42 const SilcProtocolObject silc_protocol_list[] =
43 {
44   { SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
45     silc_client_protocol_connection_auth },
46   { SILC_PROTOCOL_CLIENT_CHANNEL_AUTH, 
47     silc_client_protocol_channel_auth },
48   { SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
49     silc_client_protocol_key_exchange },
50
51   { SILC_PROTOCOL_CLIENT_NONE, NULL },
52 };
53
54 /*
55  * Key Exhange protocol functions
56  */
57
58 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
59                                                 SilcBuffer packet,
60                                                 SilcPacketType type,
61                                                 void *context)
62 {
63   SilcProtocol protocol = (SilcProtocol)context;
64   SilcClientKEInternalContext *ctx = 
65     (SilcClientKEInternalContext *)protocol->context;
66   SilcClient client = (SilcClient)ctx->client;
67
68   /* Send the packet immediately */
69   silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
70                           packet->data, packet->len, TRUE);
71
72 }
73
74 static void silc_client_protocol_ke_phase1_cb(SilcSKE ske,
75                                               void *context)
76 {
77   SilcProtocol protocol = (SilcProtocol)context;
78   SilcClientKEInternalContext *ctx = 
79     (SilcClientKEInternalContext *)protocol->context;
80   SilcClient client = (SilcClient)ctx->client;
81
82   SILC_LOG_DEBUG(("Start"));
83
84 }
85
86 static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
87                                               void *context)
88 {
89   SilcProtocol protocol = (SilcProtocol)context;
90   SilcClientKEInternalContext *ctx = 
91     (SilcClientKEInternalContext *)protocol->context;
92   SilcClient client = (SilcClient)ctx->client;
93
94   SILC_LOG_DEBUG(("Start"));
95
96 }
97
98 /* Sets the negotiated key material into use for particular connection. */
99
100 static void silc_client_protocol_ke_set_keys(SilcSKE ske,
101                                              SilcSocketConnection sock,
102                                              SilcSKEKeyMaterial *keymat,
103                                              SilcCipher cipher,
104                                              SilcPKCS pkcs,
105                                              SilcHash hash)
106 {
107   SilcClientWindow win = (SilcClientWindow)sock->user_data;
108   SilcHash nhash;
109
110   SILC_LOG_DEBUG(("Setting new keys into use"));
111
112   /* Allocate cipher to be used in the communication */
113   silc_cipher_alloc(cipher->cipher->name, &win->send_key);
114   silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
115
116   win->send_key->cipher->set_key(win->send_key->context, 
117                                  keymat->send_enc_key, 
118                                  keymat->enc_key_len);
119   win->send_key->set_iv(win->send_key, keymat->send_iv);
120   win->receive_key->cipher->set_key(win->receive_key->context, 
121                                     keymat->receive_enc_key, 
122                                     keymat->enc_key_len);
123   win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
124
125   /* Allocate PKCS to be used */
126 #if 0
127   /* XXX Do we ever need to allocate PKCS for the connection??
128      If yes, we need to change KE protocol to get the initiators
129      public key. */
130   silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
131   silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data, 
132                            ske->ke2_payload->pk_len);
133 #endif
134
135   /* Save HMAC key to be used in the communication. */
136   silc_hash_alloc(hash->hash->name, &nhash);
137   silc_hmac_alloc(nhash, &win->hmac);
138   win->hmac_key_len = keymat->hmac_key_len;
139   win->hmac_key = silc_calloc(win->hmac_key_len,
140                                     sizeof(unsigned char));
141   memcpy(win->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
142
143 }
144
145 /* Performs key exchange protocol. This is used for both initiator
146    and responder key exchange. This may be called recursively. */
147
148 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
149 {
150   SilcProtocol protocol = (SilcProtocol)context;
151   SilcClientKEInternalContext *ctx = 
152     (SilcClientKEInternalContext *)protocol->context;
153   SilcClient client = (SilcClient)ctx->client;
154   SilcSKEStatus status;
155
156   SILC_LOG_DEBUG(("Start"));
157
158   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
159     protocol->state = SILC_PROTOCOL_STATE_START;
160
161   switch(protocol->state) {
162   case SILC_PROTOCOL_STATE_START:
163     {
164       /*
165        * Start Protocol
166        */
167       SilcSKE ske;
168
169       /* Allocate Key Exchange object */
170       ske = silc_ske_alloc();
171       ctx->ske = ske;
172       
173       if (ctx->responder == TRUE) {
174 #if 0
175         SilcBuffer start_payload;
176
177
178         /* Start the key exchange by processing the received security
179            properties packet from initiator. */
180         status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
181                                           start_payload,
182                                           silc_client_protocol_ke_send_packet,
183                                           context);
184 #endif
185       } else {
186         SilcSKEStartPayload *start_payload;
187
188         /* Assemble security properties. */
189         silc_ske_assemble_security_properties(ske, &start_payload);
190
191         /* Start the key exchange by sending our security properties
192            to the remote end. */
193         status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
194                                           start_payload,
195                                           silc_client_protocol_ke_send_packet,
196                                           context);
197       }
198
199       if (status != SILC_SKE_STATUS_OK) {
200         switch(status) {
201           
202         default:
203           break;
204         }
205       }
206
207       /* Advance the state of the protocol. */
208       protocol->state++;
209     }
210     break;
211   case 2:
212     {
213       /* 
214        * Phase 1 
215        */
216       if (ctx->responder == TRUE) {
217 #if 0
218         status = 
219           silc_ske_responder_phase_1(ctx->ske, 
220                                      ctx->ske->start_payload,
221                                      silc_server_protocol_ke_send_packet,
222                                      context);
223 #endif
224       } else {
225         /* Call Phase-1 function. This processes the Key Exchange Start
226            paylaod reply we just got from the responder. The callback
227            function will receive the processed payload where we will
228            save it. */
229         status = 
230           silc_ske_initiator_phase_1(ctx->ske,
231                                      ctx->packet,
232                                      silc_client_protocol_ke_phase1_cb,
233                                      context);
234       }
235
236       switch(status) {
237       default:
238         break;
239       }
240
241       /* Advance the state of the protocol and call the next state. */
242       protocol->state++;
243       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
244     }
245     break;
246   case 3:
247     {
248       /* 
249        * Phase 2 
250        */
251       if (ctx->responder == TRUE) {
252 #if 0
253         status = 
254           silc_ske_responder_phase_2(ctx->ske, 
255                                      ctx->ske->start_payload,
256                                      silc_server_protocol_ke_send_packet,
257                                      context);
258 #endif
259       } else {
260         /* Call the Phase-2 function. This creates Diffie Hellman
261            key exchange parameters and sends our public part inside
262            Key Exhange 1 Payload to the responder. */
263         status = 
264           silc_ske_initiator_phase_2(ctx->ske,
265                                      silc_client_protocol_ke_send_packet,
266                                      context);
267       }
268
269       switch(status) {
270       default:
271         break;
272       }
273
274       /* Advance the state of the protocol. */
275       protocol->state++;
276     }
277     break;
278   case 4:
279     {
280       /* 
281        * Finish protocol
282        */
283       if (ctx->responder == TRUE) {
284 #if 0
285         status = 
286           silc_ske_responder_phase_2(ctx->ske, 
287                                      ctx->ske->start_payload,
288                                      silc_server_protocol_ke_send_packet,
289                                      context);
290 #endif
291       } else {
292         /* Finish the protocol. This verifies the Key Exchange 2 payload
293            sent by responder. */
294         status = 
295           silc_ske_initiator_finish(ctx->ske,
296                                     ctx->packet,
297                                     silc_client_protocol_ke_finish_cb,
298                                     context);
299       }
300
301       switch(status) {
302       default:
303         break;
304       }
305       
306       /* Send Ok to the other end. We will end the protocol as server
307          sends Ok to us when we will take the new keys into use. */
308       silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
309       
310       /* End the protocol on the next round */
311       protocol->state = SILC_PROTOCOL_STATE_END;
312     }
313     break;
314   case SILC_PROTOCOL_STATE_END:
315     {
316       /* 
317        * End protocol
318        */
319       SilcSKEKeyMaterial *keymat;
320
321       /* Process the key material */
322       keymat = silc_calloc(1, sizeof(*keymat));
323       silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
324
325       /* Take the negotiated keys into use. */
326       silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
327                                        ctx->ske->prop->cipher,
328                                        ctx->ske->prop->pkcs,
329                                        ctx->ske->prop->hash);
330
331       /* Protocol has ended, call the final callback */
332       if (protocol->final_callback)
333         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
334       else
335         silc_protocol_free(protocol);
336     }
337     break;
338   case SILC_PROTOCOL_STATE_ERROR:
339     
340     /* On error the final callback is always called. */
341     /*    protocol->final_callback(pptr, context);*/
342     break;
343   case SILC_PROTOCOL_STATE_UNKNOWN:
344     break;
345   }
346 }
347
348 /*
349  * Connection Authentication protocol functions
350  */
351
352 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
353 {
354   SilcProtocol protocol = (SilcProtocol)context;
355   SilcClientConnAuthInternalContext *ctx = 
356     (SilcClientConnAuthInternalContext *)protocol->context;
357   SilcClient client = (SilcClient)ctx->client;
358
359   SILC_LOG_DEBUG(("Start"));
360
361   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
362     protocol->state = SILC_PROTOCOL_STATE_START;
363
364   switch(protocol->state) {
365   case SILC_PROTOCOL_STATE_START:
366     {
367       /* 
368        * Start protocol. We send authentication data to the server
369        * to be authenticated.
370        */
371       SilcBuffer packet;
372       int payload_len = 0;
373       unsigned char *auth_data = NULL;
374       unsigned int auth_data_len = 0;
375
376       switch(ctx->auth_meth) {
377       case SILC_PROTOCOL_CONN_AUTH_NONE:
378         /* No authentication required */
379         break;
380
381       case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
382         /* Password authentication */
383         if (ctx->auth_data && ctx->auth_data_len) {
384           auth_data = ctx->auth_data;
385           auth_data_len = ctx->auth_data_len;
386           break;
387         }
388
389         silc_say(client, "Password authentication required by server %s",
390                  ctx->sock->hostname);
391         auth_data = silc_client_ask_passphrase(client);
392         auth_data_len = strlen(auth_data);
393         break;
394
395       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
396 #if 0
397
398 #endif
399         break;
400       }
401
402       payload_len = 4 + auth_data_len;
403       packet = silc_buffer_alloc(payload_len);
404       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
405       silc_buffer_format(packet,
406                          SILC_STR_UI_SHORT(payload_len),
407                          SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
408                          SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
409                          SILC_STR_END);
410
411       /* Send the packet to server */
412       silc_client_packet_send(client, ctx->sock,
413                               SILC_PACKET_CONNECTION_AUTH,
414                               NULL, 0, NULL, NULL,
415                               packet->data, packet->len, TRUE);
416
417       if (auth_data) {
418         memset(auth_data, 0, auth_data_len);
419         silc_free(auth_data);
420       }
421       silc_buffer_free(packet);
422       
423       /* Next state is end of protocol */
424       protocol->state = SILC_PROTOCOL_STATE_END;
425     }
426     break;
427
428   case SILC_PROTOCOL_STATE_END:
429     {
430       /* 
431        * End protocol. Nothing special to be done here.
432        */
433
434       /* Protocol has ended, call the final callback */
435       if (protocol->final_callback)
436         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
437       else
438         silc_protocol_free(protocol);
439     }
440     break;
441
442   case SILC_PROTOCOL_STATE_ERROR:
443     {
444       /* 
445        * Error
446        */
447
448       /* Error in protocol. Send FAILURE packet. Although I don't think
449          this could ever happen on client side. */
450       silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
451                               NULL, 0, NULL, NULL, NULL, 0, TRUE);
452
453       /* On error the final callback is always called. */
454       if (protocol->final_callback)
455         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
456       else
457         silc_protocol_free(protocol);
458     }
459     break;
460   case SILC_PROTOCOL_STATE_UNKNOWN:
461     break;
462   }
463 }
464
465 SILC_TASK_CALLBACK(silc_client_protocol_channel_auth)
466 {
467 }