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