Minor ops API change and bugfixes.
[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 = 0;
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         SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
180                           status));
181         SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
182                         status));
183
184         protocol->state = SILC_PROTOCOL_STATE_ERROR;
185         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
186         return;
187       }
188
189       /* Advance the state of the protocol. */
190       protocol->state++;
191     }
192     break;
193   case 2:
194     {
195       /* 
196        * Phase 1 
197        */
198       if (ctx->responder == TRUE) {
199 #if 0
200         status = 
201           silc_ske_responder_phase_1(ctx->ske, 
202                                      ctx->ske->start_payload,
203                                      silc_server_protocol_ke_send_packet,
204                                      context);
205 #endif
206       } else {
207         /* Call Phase-1 function. This processes the Key Exchange Start
208            paylaod reply we just got from the responder. The callback
209            function will receive the processed payload where we will
210            save it. */
211         status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet, NULL, NULL);
212       }
213
214       if (status != SILC_SKE_STATUS_OK) {
215         SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
216                           status));
217         SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
218                         status));
219
220         protocol->state = SILC_PROTOCOL_STATE_ERROR;
221         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
222         return;
223       }
224
225       /* Advance the state of the protocol and call the next state. */
226       protocol->state++;
227       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
228     }
229     break;
230   case 3:
231     {
232       /* 
233        * Phase 2 
234        */
235       if (ctx->responder == TRUE) {
236 #if 0
237         status = 
238           silc_ske_responder_phase_2(ctx->ske, 
239                                      ctx->ske->start_payload,
240                                      silc_server_protocol_ke_send_packet,
241                                      context);
242 #endif
243       } else {
244         /* Call the Phase-2 function. This creates Diffie Hellman
245            key exchange parameters and sends our public part inside
246            Key Exhange 1 Payload to the responder. */
247         status = 
248           silc_ske_initiator_phase_2(ctx->ske,
249                                      client->public_key,
250                                      silc_client_protocol_ke_send_packet,
251                                      context);
252       }
253
254       if (status != SILC_SKE_STATUS_OK) {
255         SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
256                           status));
257         SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
258                         status));
259
260         protocol->state = SILC_PROTOCOL_STATE_ERROR;
261         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
262         return;
263       }
264
265       /* Advance the state of the protocol. */
266       protocol->state++;
267     }
268     break;
269   case 4:
270     {
271       /* 
272        * Finish protocol
273        */
274       if (ctx->responder == TRUE) {
275         status = 0;
276 #if 0
277         status = 
278           silc_ske_responder_phase_2(ctx->ske, 
279                                      ctx->ske->start_payload,
280                                      silc_server_protocol_ke_send_packet,
281                                      context);
282 #endif
283       } else {
284         /* Finish the protocol. This verifies the Key Exchange 2 payload
285            sent by responder. */
286         status = silc_ske_initiator_finish(ctx->ske, ctx->packet,
287                                            silc_client_protocol_ke_verify_key,
288                                            context, NULL, NULL);
289       }
290
291       if (status != SILC_SKE_STATUS_OK) {
292
293         if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
294           client->ops->say(client, conn, 
295                            "Received unsupported server %s public key",
296                            ctx->sock->hostname);
297         } else {
298           client->ops->say(client, conn,
299                            "Error during key exchange protocol with server %s",
300                            ctx->sock->hostname);
301         }
302         protocol->state = SILC_PROTOCOL_STATE_ERROR;
303         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
304         return;
305       }
306       
307       /* Send Ok to the other end. We will end the protocol as server
308          sends Ok to us when we will take the new keys into use. */
309       silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
310       
311       /* End the protocol on the next round */
312       protocol->state = SILC_PROTOCOL_STATE_END;
313     }
314     break;
315   case SILC_PROTOCOL_STATE_END:
316     {
317       /* 
318        * End protocol
319        */
320       SilcSKEKeyMaterial *keymat;
321
322       /* Process the key material */
323       keymat = silc_calloc(1, sizeof(*keymat));
324       silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
325
326       /* Take the negotiated keys into use. */
327       silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
328                                        ctx->ske->prop->cipher,
329                                        ctx->ske->prop->pkcs,
330                                        ctx->ske->prop->hash);
331
332       /* Protocol has ended, call the final callback */
333       if (protocol->final_callback)
334         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
335       else
336         silc_protocol_free(protocol);
337     }
338     break;
339   case SILC_PROTOCOL_STATE_ERROR:
340     
341     /* On error the final callback is always called. */
342     if (protocol->final_callback)
343       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
344     else
345       silc_protocol_free(protocol);
346     break;
347   case SILC_PROTOCOL_STATE_UNKNOWN:
348     break;
349   }
350 }
351
352 /*
353  * Connection Authentication protocol functions
354  */
355
356 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
357 {
358   SilcProtocol protocol = (SilcProtocol)context;
359   SilcClientConnAuthInternalContext *ctx = 
360     (SilcClientConnAuthInternalContext *)protocol->context;
361   SilcClient client = (SilcClient)ctx->client;
362   SilcClientConnection conn = ctx->sock->user_data;
363
364   SILC_LOG_DEBUG(("Start"));
365
366   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
367     protocol->state = SILC_PROTOCOL_STATE_START;
368
369   switch(protocol->state) {
370   case SILC_PROTOCOL_STATE_START:
371     {
372       /* 
373        * Start protocol. We send authentication data to the server
374        * to be authenticated.
375        */
376       SilcBuffer packet;
377       int payload_len = 0;
378       unsigned char *auth_data = NULL;
379       unsigned int auth_data_len = 0;
380
381       switch(ctx->auth_meth) {
382       case SILC_PROTOCOL_CONN_AUTH_NONE:
383         /* No authentication required */
384         break;
385
386       case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
387         /* Password authentication */
388         if (ctx->auth_data && ctx->auth_data_len) {
389           auth_data = ctx->auth_data;
390           auth_data_len = ctx->auth_data_len;
391           break;
392         }
393
394         client->ops->say(client, conn, 
395                          "Password authentication required by server %s",
396                          ctx->sock->hostname);
397         auth_data = client->ops->ask_passphrase(client, conn);
398         auth_data_len = strlen(auth_data);
399         break;
400
401       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
402         /* XXX */
403         break;
404       }
405
406       payload_len = 4 + auth_data_len;
407       packet = silc_buffer_alloc(payload_len);
408       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
409       silc_buffer_format(packet,
410                          SILC_STR_UI_SHORT(payload_len),
411                          SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
412                          SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
413                          SILC_STR_END);
414
415       /* Send the packet to server */
416       silc_client_packet_send(client, ctx->sock,
417                               SILC_PACKET_CONNECTION_AUTH,
418                               NULL, 0, NULL, NULL,
419                               packet->data, packet->len, TRUE);
420
421       if (auth_data) {
422         memset(auth_data, 0, auth_data_len);
423         silc_free(auth_data);
424       }
425       silc_buffer_free(packet);
426       
427       /* Next state is end of protocol */
428       protocol->state = SILC_PROTOCOL_STATE_END;
429     }
430     break;
431
432   case SILC_PROTOCOL_STATE_END:
433     {
434       /* 
435        * End protocol. Nothing special to be done here.
436        */
437
438       /* Protocol has ended, call the final callback */
439       if (protocol->final_callback)
440         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
441       else
442         silc_protocol_free(protocol);
443     }
444     break;
445
446   case SILC_PROTOCOL_STATE_ERROR:
447     {
448       /* 
449        * Error
450        */
451
452       /* Error in protocol. Send FAILURE packet. Although I don't think
453          this could ever happen on client side. */
454       silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
455                               NULL, 0, NULL, NULL, NULL, 0, TRUE);
456
457       /* On error the final callback is always called. */
458       if (protocol->final_callback)
459         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
460       else
461         silc_protocol_free(protocol);
462     }
463     break;
464   case SILC_PROTOCOL_STATE_UNKNOWN:
465     break;
466   }
467 }
468
469 /* Registers protocols used in client */
470
471 void silc_client_protocols_register(void)
472 {
473   silc_protocol_register(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
474                          silc_client_protocol_connection_auth);
475   silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
476                          silc_client_protocol_key_exchange);
477 }
478
479 /* Unregisters protocols */
480
481 void silc_client_protocols_unregister(void)
482 {
483   silc_protocol_unregister(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
484                            silc_client_protocol_connection_auth);
485   silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
486                            silc_client_protocol_key_exchange);
487 }