Initial revision
[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.1  2000/06/27 11:36:56  priikone
27  * Initial revision
28  *
29  *
30  */
31
32 #include "clientincludes.h"
33
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);
37
38 /* SILC client protocol list */
39 const SilcProtocolObject silc_protocol_list[] =
40 {
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 },
47
48   { SILC_PROTOCOL_CLIENT_NONE, NULL },
49 };
50
51 /*
52  * Key Exhange protocol functions
53  */
54
55 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
56                                                 SilcBuffer packet,
57                                                 SilcPacketType type,
58                                                 void *context)
59 {
60   SilcProtocol protocol = (SilcProtocol)context;
61   SilcClientKEInternalContext *ctx = 
62     (SilcClientKEInternalContext *)protocol->context;
63   SilcClient client = (SilcClient)ctx->client;
64
65   /* Send the packet immediately */
66   silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
67                           packet->data, packet->len, TRUE);
68
69 }
70
71 static void silc_client_protocol_ke_phase1_cb(SilcSKE ske,
72                                               void *context)
73 {
74   SilcProtocol protocol = (SilcProtocol)context;
75   SilcClientKEInternalContext *ctx = 
76     (SilcClientKEInternalContext *)protocol->context;
77   SilcClient client = (SilcClient)ctx->client;
78
79   SILC_LOG_DEBUG(("Start"));
80
81 }
82
83 static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
84                                               void *context)
85 {
86   SilcProtocol protocol = (SilcProtocol)context;
87   SilcClientKEInternalContext *ctx = 
88     (SilcClientKEInternalContext *)protocol->context;
89   SilcClient client = (SilcClient)ctx->client;
90
91   SILC_LOG_DEBUG(("Start"));
92
93 }
94
95 /* Sets the negotiated key material into use for particular connection. */
96
97 static void silc_client_protocol_ke_set_keys(SilcSKE ske,
98                                              SilcSocketConnection sock,
99                                              SilcSKEKeyMaterial *keymat,
100                                              SilcCipher cipher,
101                                              SilcPKCS pkcs,
102                                              SilcHash hash)
103 {
104   SilcClientWindow win = (SilcClientWindow)sock->user_data;
105   SilcHash nhash;
106
107   SILC_LOG_DEBUG(("Setting new keys into use"));
108
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);
112
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);
121
122   /* Allocate PKCS to be used */
123 #if 0
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
126      public key. */
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);
130 #endif
131
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);
139
140 }
141
142 /* Performs key exchange protocol. This is used for both initiator
143    and responder key exchange. This may be called recursively. */
144
145 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
146 {
147   SilcProtocol protocol = (SilcProtocol)context;
148   SilcClientKEInternalContext *ctx = 
149     (SilcClientKEInternalContext *)protocol->context;
150   SilcClient client = (SilcClient)ctx->client;
151   SilcSKEStatus status;
152
153   SILC_LOG_DEBUG(("Start"));
154
155   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
156     protocol->state = SILC_PROTOCOL_STATE_START;
157
158   switch(protocol->state) {
159   case SILC_PROTOCOL_STATE_START:
160     {
161       /*
162        * Start Protocol
163        */
164       SilcSKE ske;
165
166       /* Allocate Key Exchange object */
167       ske = silc_ske_alloc();
168       ctx->ske = ske;
169       
170       if (ctx->responder == TRUE) {
171 #if 0
172         SilcBuffer start_payload;
173
174
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,
178                                           start_payload,
179                                           silc_client_protocol_ke_send_packet,
180                                           context);
181 #endif
182       } else {
183         SilcSKEStartPayload *start_payload;
184
185         /* Assemble security properties. */
186         silc_ske_assemble_security_properties(ske, &start_payload);
187
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,
191                                           start_payload,
192                                           silc_client_protocol_ke_send_packet,
193                                           context);
194       }
195
196       if (status != SILC_SKE_STATUS_OK) {
197         switch(status) {
198           
199         default:
200           break;
201         }
202       }
203
204       /* Advance the state of the protocol. */
205       protocol->state++;
206     }
207     break;
208   case 2:
209     {
210       /* 
211        * Phase 1 
212        */
213       if (ctx->responder == TRUE) {
214 #if 0
215         status = 
216           silc_ske_responder_phase_1(ctx->ske, 
217                                      ctx->ske->start_payload,
218                                      silc_server_protocol_ke_send_packet,
219                                      context);
220 #endif
221       } else {
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
225            save it. */
226         status = 
227           silc_ske_initiator_phase_1(ctx->ske,
228                                      ctx->packet,
229                                      silc_client_protocol_ke_phase1_cb,
230                                      context);
231       }
232
233       switch(status) {
234       default:
235         break;
236       }
237
238       /* Advance the state of the protocol and call the next state. */
239       protocol->state++;
240       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
241     }
242     break;
243   case 3:
244     {
245       /* 
246        * Phase 2 
247        */
248       if (ctx->responder == TRUE) {
249 #if 0
250         status = 
251           silc_ske_responder_phase_2(ctx->ske, 
252                                      ctx->ske->start_payload,
253                                      silc_server_protocol_ke_send_packet,
254                                      context);
255 #endif
256       } else {
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. */
260         status = 
261           silc_ske_initiator_phase_2(ctx->ske,
262                                      silc_client_protocol_ke_send_packet,
263                                      context);
264       }
265
266       switch(status) {
267       default:
268         break;
269       }
270
271       /* Advance the state of the protocol. */
272       protocol->state++;
273     }
274     break;
275   case 4:
276     {
277       /* 
278        * Finish protocol
279        */
280       if (ctx->responder == TRUE) {
281 #if 0
282         status = 
283           silc_ske_responder_phase_2(ctx->ske, 
284                                      ctx->ske->start_payload,
285                                      silc_server_protocol_ke_send_packet,
286                                      context);
287 #endif
288       } else {
289         /* Finish the protocol. This verifies the Key Exchange 2 payload
290            sent by responder. */
291         status = 
292           silc_ske_initiator_finish(ctx->ske,
293                                     ctx->packet,
294                                     silc_client_protocol_ke_finish_cb,
295                                     context);
296       }
297
298       switch(status) {
299       default:
300         break;
301       }
302       
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);
306       
307       /* End the protocol on the next round */
308       protocol->state = SILC_PROTOCOL_STATE_END;
309     }
310     break;
311   case SILC_PROTOCOL_STATE_END:
312     {
313       /* 
314        * End protocol
315        */
316       SilcSKEKeyMaterial *keymat;
317
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);
321
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);
327
328       /* Protocol has ended, call the final callback */
329       if (protocol->final_callback)
330         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
331       else
332         silc_protocol_free(protocol);
333     }
334     break;
335   case SILC_PROTOCOL_STATE_ERROR:
336     
337     /* On error the final callback is always called. */
338     /*    protocol->final_callback(pptr, context);*/
339     break;
340   case SILC_PROTOCOL_STATE_UNKNOWN:
341     break;
342   }
343 }
344
345 /*
346  * Connection Authentication protocol functions
347  */
348
349 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
350 {
351   SilcProtocol protocol = (SilcProtocol)context;
352   SilcClientConnAuthInternalContext *ctx = 
353     (SilcClientConnAuthInternalContext *)protocol->context;
354   SilcClient client = (SilcClient)ctx->client;
355
356   SILC_LOG_DEBUG(("Start"));
357
358   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
359     protocol->state = SILC_PROTOCOL_STATE_START;
360
361   switch(protocol->state) {
362   case SILC_PROTOCOL_STATE_START:
363     {
364       /* 
365        * Start protocol. We send authentication data to the server
366        * to be authenticated.
367        */
368       SilcBuffer packet;
369       int payload_len = 0;
370       unsigned char *auth_data = NULL;
371       unsigned int auth_data_len = 0;
372
373       switch(ctx->auth_meth) {
374       case SILC_PROTOCOL_CONN_AUTH_NONE:
375         /* No authentication required */
376         break;
377
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;
383           break;
384         }
385
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);
390         break;
391
392       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
393 #if 0
394
395 #endif
396         break;
397       }
398
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),
406                          SILC_STR_END);
407
408       /* Send the packet to server */
409       silc_client_packet_send(client, ctx->sock,
410                               SILC_PACKET_CONNECTION_AUTH,
411                               NULL, 0, NULL, NULL,
412                               packet->data, packet->len, TRUE);
413
414       if (auth_data) {
415         memset(auth_data, 0, auth_data_len);
416         silc_free(auth_data);
417       }
418       silc_buffer_free(packet);
419       
420       /* Next state is end of protocol */
421       protocol->state = SILC_PROTOCOL_STATE_END;
422     }
423     break;
424
425   case SILC_PROTOCOL_STATE_END:
426     {
427       /* 
428        * End protocol. Nothing special to be done here.
429        */
430
431       /* Protocol has ended, call the final callback */
432       if (protocol->final_callback)
433         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
434       else
435         silc_protocol_free(protocol);
436     }
437     break;
438
439   case SILC_PROTOCOL_STATE_ERROR:
440     {
441       /* 
442        * Error
443        */
444
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);
449
450       /* On error the final callback is always called. */
451       if (protocol->final_callback)
452         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
453       else
454         silc_protocol_free(protocol);
455     }
456     break;
457   case SILC_PROTOCOL_STATE_UNKNOWN:
458     break;
459   }
460 }
461
462 SILC_TASK_CALLBACK(silc_client_protocol_channel_auth)
463 {
464 }