Splitted SILC core library. Core library includes now only
[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.8  2000/07/20 10:17:25  priikone
27  *      Added dynamic protocol registering/unregistering support.  The
28  *      patch was provided by cras.
29  *
30  * Revision 1.7  2000/07/19 07:07:47  priikone
31  *      Added version detection support to SKE.
32  *
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.
37  *
38  * Revision 1.5  2000/07/07 11:36:09  priikone
39  *      Inform user when received unsupported public key from server.
40  *
41  * Revision 1.4  2000/07/07 06:53:45  priikone
42  *      Added support for server public key verification.
43  *
44  * Revision 1.3  2000/07/06 07:14:16  priikone
45  *      Deprecated old `channel_auth' protocol.
46  *
47  * Revision 1.2  2000/07/05 06:12:05  priikone
48  *      Global cosmetic changes.
49  *
50  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
51  *      Imported from internal CVS/Added Log headers.
52  *
53  *
54  */
55
56 #include "clientincludes.h"
57
58 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
59 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
60
61 extern char *silc_version_string;
62
63 /*
64  * Key Exhange protocol functions
65  */
66
67 /* Function that is called when SKE protocol sends packets to network. */
68
69 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
70                                                 SilcBuffer packet,
71                                                 SilcPacketType type,
72                                                 void *context)
73 {
74   SilcProtocol protocol = (SilcProtocol)context;
75   SilcClientKEInternalContext *ctx = 
76     (SilcClientKEInternalContext *)protocol->context;
77   SilcClient client = (SilcClient)ctx->client;
78
79   /* Send the packet immediately */
80   silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
81                           packet->data, packet->len, TRUE);
82
83 }
84
85 /* Callback that is called when we have received KE2 payload from
86    responder. We try to verify the public key now. */
87
88 static SilcSKEStatus 
89 silc_client_protocol_ke_verify_key(SilcSKE ske,
90                                    unsigned char *pk_data,
91                                    unsigned int pk_len,
92                                    SilcSKEPKType pk_type,
93                                    void *context)
94 {
95   SilcProtocol protocol = (SilcProtocol)context;
96   SilcClientKEInternalContext *ctx = 
97     (SilcClientKEInternalContext *)protocol->context;
98   SilcClient client = (SilcClient)ctx->client;
99
100   SILC_LOG_DEBUG(("Start"));
101
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;
105
106   return SILC_SKE_STATUS_OK;
107 }
108
109 /* Sets the negotiated key material into use for particular connection. */
110
111 static void silc_client_protocol_ke_set_keys(SilcSKE ske,
112                                              SilcSocketConnection sock,
113                                              SilcSKEKeyMaterial *keymat,
114                                              SilcCipher cipher,
115                                              SilcPKCS pkcs,
116                                              SilcHash hash)
117 {
118   SilcClientWindow win = (SilcClientWindow)sock->user_data;
119   SilcHash nhash;
120
121   SILC_LOG_DEBUG(("Setting new keys into use"));
122
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);
126
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);
135
136   /* Allocate PKCS to be used */
137 #if 0
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
140      public key. */
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);
144 #endif
145
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);
150 }
151
152 /* Performs key exchange protocol. This is used for both initiator
153    and responder key exchange. This may be called recursively. */
154
155 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
156 {
157   SilcProtocol protocol = (SilcProtocol)context;
158   SilcClientKEInternalContext *ctx = 
159     (SilcClientKEInternalContext *)protocol->context;
160   SilcClient client = (SilcClient)ctx->client;
161   SilcSKEStatus status;
162
163   SILC_LOG_DEBUG(("Start"));
164
165   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
166     protocol->state = SILC_PROTOCOL_STATE_START;
167
168   switch(protocol->state) {
169   case SILC_PROTOCOL_STATE_START:
170     {
171       /*
172        * Start Protocol
173        */
174       SilcSKE ske;
175
176       /* Allocate Key Exchange object */
177       ske = silc_ske_alloc();
178       ctx->ske = ske;
179       
180       if (ctx->responder == TRUE) {
181 #if 0
182         SilcBuffer start_payload;
183
184
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,
188                                           start_payload,
189                                           silc_client_protocol_ke_send_packet,
190                                           context);
191 #endif
192       } else {
193         SilcSKEStartPayload *start_payload;
194
195         /* Assemble security properties. */
196         silc_ske_assemble_security_properties(ske, silc_version_string,
197                                               &start_payload);
198
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,
202                                           start_payload,
203                                           silc_client_protocol_ke_send_packet,
204                                           context);
205       }
206
207       if (status != SILC_SKE_STATUS_OK) {
208         switch(status) {
209           
210         default:
211           break;
212         }
213       }
214
215       /* Advance the state of the protocol. */
216       protocol->state++;
217     }
218     break;
219   case 2:
220     {
221       /* 
222        * Phase 1 
223        */
224       if (ctx->responder == TRUE) {
225 #if 0
226         status = 
227           silc_ske_responder_phase_1(ctx->ske, 
228                                      ctx->ske->start_payload,
229                                      silc_server_protocol_ke_send_packet,
230                                      context);
231 #endif
232       } else {
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
236            save it. */
237         status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet, NULL, NULL);
238       }
239
240       switch(status) {
241       default:
242         break;
243       }
244
245       /* Advance the state of the protocol and call the next state. */
246       protocol->state++;
247       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
248     }
249     break;
250   case 3:
251     {
252       /* 
253        * Phase 2 
254        */
255       if (ctx->responder == TRUE) {
256 #if 0
257         status = 
258           silc_ske_responder_phase_2(ctx->ske, 
259                                      ctx->ske->start_payload,
260                                      silc_server_protocol_ke_send_packet,
261                                      context);
262 #endif
263       } else {
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. */
267         status = 
268           silc_ske_initiator_phase_2(ctx->ske,
269                                      client->public_key,
270                                      silc_client_protocol_ke_send_packet,
271                                      context);
272       }
273
274       switch(status) {
275       default:
276         break;
277       }
278
279       /* Advance the state of the protocol. */
280       protocol->state++;
281     }
282     break;
283   case 4:
284     {
285       /* 
286        * Finish protocol
287        */
288       if (ctx->responder == TRUE) {
289         status = 0;
290 #if 0
291         status = 
292           silc_ske_responder_phase_2(ctx->ske, 
293                                      ctx->ske->start_payload,
294                                      silc_server_protocol_ke_send_packet,
295                                      context);
296 #endif
297       } else {
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);
303       }
304
305       if (status != SILC_SKE_STATUS_OK) {
306
307         if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
308           silc_say(client, "Received unsupported server %s public key",
309                    ctx->sock->hostname);
310         } else {
311           silc_say(client, "Error during key exchange protocol with server %s",
312                    ctx->sock->hostname);
313         }
314         protocol->state = SILC_PROTOCOL_STATE_ERROR;
315         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
316         return;
317       }
318       
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);
322       
323       /* End the protocol on the next round */
324       protocol->state = SILC_PROTOCOL_STATE_END;
325     }
326     break;
327   case SILC_PROTOCOL_STATE_END:
328     {
329       /* 
330        * End protocol
331        */
332       SilcSKEKeyMaterial *keymat;
333
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);
337
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);
343
344       /* Protocol has ended, call the final callback */
345       if (protocol->final_callback)
346         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
347       else
348         silc_protocol_free(protocol);
349     }
350     break;
351   case SILC_PROTOCOL_STATE_ERROR:
352     
353     /* On error the final callback is always called. */
354     if (protocol->final_callback)
355       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
356     else
357       silc_protocol_free(protocol);
358     break;
359   case SILC_PROTOCOL_STATE_UNKNOWN:
360     break;
361   }
362 }
363
364 /*
365  * Connection Authentication protocol functions
366  */
367
368 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
369 {
370   SilcProtocol protocol = (SilcProtocol)context;
371   SilcClientConnAuthInternalContext *ctx = 
372     (SilcClientConnAuthInternalContext *)protocol->context;
373   SilcClient client = (SilcClient)ctx->client;
374
375   SILC_LOG_DEBUG(("Start"));
376
377   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
378     protocol->state = SILC_PROTOCOL_STATE_START;
379
380   switch(protocol->state) {
381   case SILC_PROTOCOL_STATE_START:
382     {
383       /* 
384        * Start protocol. We send authentication data to the server
385        * to be authenticated.
386        */
387       SilcBuffer packet;
388       int payload_len = 0;
389       unsigned char *auth_data = NULL;
390       unsigned int auth_data_len = 0;
391
392       switch(ctx->auth_meth) {
393       case SILC_PROTOCOL_CONN_AUTH_NONE:
394         /* No authentication required */
395         break;
396
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;
402           break;
403         }
404
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);
409         break;
410
411       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
412         /* XXX */
413         break;
414       }
415
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),
423                          SILC_STR_END);
424
425       /* Send the packet to server */
426       silc_client_packet_send(client, ctx->sock,
427                               SILC_PACKET_CONNECTION_AUTH,
428                               NULL, 0, NULL, NULL,
429                               packet->data, packet->len, TRUE);
430
431       if (auth_data) {
432         memset(auth_data, 0, auth_data_len);
433         silc_free(auth_data);
434       }
435       silc_buffer_free(packet);
436       
437       /* Next state is end of protocol */
438       protocol->state = SILC_PROTOCOL_STATE_END;
439     }
440     break;
441
442   case SILC_PROTOCOL_STATE_END:
443     {
444       /* 
445        * End protocol. Nothing special to be done here.
446        */
447
448       /* Protocol has ended, call the final callback */
449       if (protocol->final_callback)
450         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
451       else
452         silc_protocol_free(protocol);
453     }
454     break;
455
456   case SILC_PROTOCOL_STATE_ERROR:
457     {
458       /* 
459        * Error
460        */
461
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);
466
467       /* On error the final callback is always called. */
468       if (protocol->final_callback)
469         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
470       else
471         silc_protocol_free(protocol);
472     }
473     break;
474   case SILC_PROTOCOL_STATE_UNKNOWN:
475     break;
476   }
477 }
478
479 /* Registers protocols used in client */
480
481 void silc_client_protocols_register(void)
482 {
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);
487 }
488
489 /* Unregisters protocols */
490
491 void silc_client_protocols_unregister(void)
492 {
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);
497 }