updates.
[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 - 2001 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 #include "client_internal.h"
27
28 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
29 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
30 SILC_TASK_CALLBACK(silc_client_protocol_rekey);
31
32 extern char *silc_version_string;
33
34 /*
35  * Key Exhange protocol functions
36  */
37
38 /* Function that is called when SKE protocol sends packets to network. */
39
40 void silc_client_protocol_ke_send_packet(SilcSKE ske,
41                                          SilcBuffer packet,
42                                          SilcPacketType type,
43                                          void *context)
44 {
45   SilcProtocol protocol = (SilcProtocol)context;
46   SilcClientKEInternalContext *ctx = 
47     (SilcClientKEInternalContext *)protocol->context;
48   SilcClient client = (SilcClient)ctx->client;
49
50   /* Send the packet immediately */
51   silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
52                           packet->data, packet->len, TRUE);
53 }
54
55 /* Callback that is called when we have received KE2 payload from
56    responder. We try to verify the public key now. */
57
58 SilcSKEStatus silc_client_protocol_ke_verify_key(SilcSKE ske,
59                                                  unsigned char *pk_data,
60                                                  uint32 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 public key from user. */
72   if (!client->ops->verify_public_key(client, ctx->sock->user_data, 
73                                       ctx->sock->type,
74                                       pk_data, pk_len, pk_type))
75     return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
76
77   return SILC_SKE_STATUS_OK;
78 }
79
80 /* Sets the negotiated key material into use for particular connection. */
81
82 void silc_client_protocol_ke_set_keys(SilcSKE ske,
83                                       SilcSocketConnection sock,
84                                       SilcSKEKeyMaterial *keymat,
85                                       SilcCipher cipher,
86                                       SilcPKCS pkcs,
87                                       SilcHash hash,
88                                       SilcHmac hmac,
89                                       SilcSKEDiffieHellmanGroup group)
90 {
91   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
92
93   SILC_LOG_DEBUG(("Setting new keys into use"));
94
95   /* Allocate cipher to be used in the communication */
96   silc_cipher_alloc(cipher->cipher->name, &conn->send_key);
97   silc_cipher_alloc(cipher->cipher->name, &conn->receive_key);
98
99   conn->send_key->cipher->set_key(conn->send_key->context, 
100                                  keymat->send_enc_key, 
101                                  keymat->enc_key_len);
102   conn->send_key->set_iv(conn->send_key, keymat->send_iv);
103   conn->receive_key->cipher->set_key(conn->receive_key->context, 
104                                     keymat->receive_enc_key, 
105                                     keymat->enc_key_len);
106   conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv);
107
108   /* Allocate PKCS to be used */
109 #if 0
110   /* XXX Do we ever need to allocate PKCS for the connection??
111      If yes, we need to change KE protocol to get the initiators
112      public key. */
113   silc_pkcs_alloc(pkcs->pkcs->name, &conn->public_Key);
114   silc_pkcs_set_public_key(conn->public_key, ske->ke2_payload->pk_data, 
115                            ske->ke2_payload->pk_len);
116 #endif
117
118   conn->rekey = silc_calloc(1, sizeof(*conn->rekey));
119   conn->rekey->send_enc_key = 
120     silc_calloc(keymat->enc_key_len / 8,
121                 sizeof(*conn->rekey->send_enc_key));
122   memcpy(conn->rekey->send_enc_key, 
123          keymat->send_enc_key, keymat->enc_key_len / 8);
124   conn->rekey->enc_key_len = keymat->enc_key_len / 8;
125
126   if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
127     conn->rekey->pfs = TRUE;
128   conn->rekey->ske_group = silc_ske_group_get_number(group);
129
130   /* Save HMAC key to be used in the communication. */
131   silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac);
132   silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
133
134   /* Save the HASH function */
135   silc_hash_alloc(hash->hash->name, &conn->hash);
136 }
137
138 /* Checks the version string of the server. */
139
140 SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
141                                      uint32 len)
142 {
143   SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data;
144   SilcClient client = (SilcClient)ske->user_data;
145   SilcSKEStatus status = SILC_SKE_STATUS_OK;
146
147   /* Check for initial version string */
148   if (!strstr(version, "SILC-1.0-"))
149     status = SILC_SKE_STATUS_BAD_VERSION;
150
151   /* Check software version */
152
153   if (len < strlen(silc_version_string))
154     status = SILC_SKE_STATUS_BAD_VERSION;
155
156   /* XXX for now there is no other tests due to the abnormal version
157      string that is used */
158
159   if (status != SILC_SKE_STATUS_OK)
160     client->ops->say(client, conn, 
161                      "We don't support server version `%s'", version);
162
163   return status;
164 }
165
166 /* Performs key exchange protocol. This is used for both initiator
167    and responder key exchange. This may be called recursively. */
168
169 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
170 {
171   SilcProtocol protocol = (SilcProtocol)context;
172   SilcClientKEInternalContext *ctx = 
173     (SilcClientKEInternalContext *)protocol->context;
174   SilcClient client = (SilcClient)ctx->client;
175   SilcClientConnection conn = ctx->sock->user_data;
176   SilcSKEStatus status = 0;
177
178   SILC_LOG_DEBUG(("Start"));
179
180   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
181     protocol->state = SILC_PROTOCOL_STATE_START;
182
183   switch(protocol->state) {
184   case SILC_PROTOCOL_STATE_START:
185     {
186       /*
187        * Start Protocol
188        */
189       SilcSKE ske;
190
191       /* Allocate Key Exchange object */
192       ske = silc_ske_alloc();
193       ctx->ske = ske;
194       ske->rng = client->rng;
195       ske->user_data = (void *)client;
196       
197       if (ctx->responder == TRUE) {
198         /* Start the key exchange by processing the received security
199            properties packet from initiator. */
200         status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
201                                           silc_version_string,
202                                           ctx->packet->buffer, TRUE,
203                                           NULL, NULL);
204       } else {
205         SilcSKEStartPayload *start_payload;
206
207         /* Assemble security properties. */
208         silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE, 
209                                               silc_version_string,
210                                               &start_payload);
211
212         /* Start the key exchange by sending our security properties
213            to the remote end. */
214         status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
215                                           start_payload,
216                                           ctx->send_packet,
217                                           context);
218       }
219
220       if (status != SILC_SKE_STATUS_OK) {
221         SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
222                           status));
223         SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
224                         status));
225
226         protocol->state = SILC_PROTOCOL_STATE_ERROR;
227         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
228         return;
229       }
230
231       /* Advance protocol state and call the next state if we are responder */
232       protocol->state++;
233       if (ctx->responder == TRUE)
234         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000);
235     }
236     break;
237   case 2:
238     {
239       /* 
240        * Phase 1 
241        */
242       if (ctx->responder == TRUE) {
243         /* Sends the selected security properties to the initiator. */
244         status = 
245           silc_ske_responder_phase_1(ctx->ske, 
246                                      ctx->ske->start_payload,
247                                      ctx->send_packet,
248                                      context);
249       } else {
250         /* Call Phase-1 function. This processes the Key Exchange Start
251            paylaod reply we just got from the responder. The callback
252            function will receive the processed payload where we will
253            save it. */
254         status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer, 
255                                             NULL, NULL);
256       }
257
258       if (status != SILC_SKE_STATUS_OK) {
259         SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
260                           status));
261         SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
262                         status));
263
264         protocol->state = SILC_PROTOCOL_STATE_ERROR;
265         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
266         return;
267       }
268
269       /* Advance protocol state and call next state if we are initiator */
270       protocol->state++;
271       if (ctx->responder == FALSE)
272         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000);
273     }
274     break;
275   case 3:
276     {
277       /* 
278        * Phase 2 
279        */
280       if (ctx->responder == TRUE) {
281         /* Process the received Key Exchange 1 Payload packet from
282            the initiator. This also creates our parts of the Diffie
283            Hellman algorithm. */
284         status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, 
285                                             ctx->verify, context, NULL, NULL);
286       } else {
287         /* Call the Phase-2 function. This creates Diffie Hellman
288            key exchange parameters and sends our public part inside
289            Key Exhange 1 Payload to the responder. */
290         status = silc_ske_initiator_phase_2(ctx->ske,
291                                             client->public_key,
292                                             client->private_key,
293                                             ctx->send_packet,
294                                             context);
295       }
296
297       if (status != SILC_SKE_STATUS_OK) {
298         SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
299                           status));
300         SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
301                         status));
302
303         protocol->state = SILC_PROTOCOL_STATE_ERROR;
304         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
305         return;
306       }
307
308       /* Advance protocol state and call the next state if we are responder */
309       protocol->state++;
310       if (ctx->responder == TRUE)
311         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 100000);
312     }
313     break;
314   case 4:
315     {
316       /* 
317        * Finish protocol
318        */
319       if (ctx->responder == TRUE) {
320         /* This creates the key exchange material and sends our
321            public parts to the initiator inside Key Exchange 2 Payload. */
322         status = 
323           silc_ske_responder_finish(ctx->ske, 
324                                     client->public_key, client->private_key,
325                                     SILC_SKE_PK_TYPE_SILC,
326                                     ctx->send_packet,
327                                     context);
328         status = 0;
329       } else {
330         /* Finish the protocol. This verifies the Key Exchange 2 payload
331            sent by responder. */
332         status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
333                                            ctx->verify, context, NULL, NULL);
334       }
335
336       if (status != SILC_SKE_STATUS_OK) {
337
338         if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
339           client->ops->say(client, conn, 
340                            "Received unsupported server %s public key",
341                            ctx->sock->hostname);
342         } else {
343           client->ops->say(client, conn,
344                            "Error during key exchange protocol with server %s",
345                            ctx->sock->hostname);
346         }
347         protocol->state = SILC_PROTOCOL_STATE_ERROR;
348         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
349         return;
350       }
351       
352       /* Send Ok to the other end. We will end the protocol as server
353          sends Ok to us when we will take the new keys into use. */
354       if (ctx->responder == FALSE)
355         silc_ske_end(ctx->ske, ctx->send_packet, context);
356       
357       /* End the protocol on the next round */
358       protocol->state = SILC_PROTOCOL_STATE_END;
359     }
360     break;
361
362   case SILC_PROTOCOL_STATE_END:
363     {
364       /* 
365        * End protocol
366        */
367       SilcSKEKeyMaterial *keymat;
368       int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher);
369       int hash_len = ctx->ske->prop->hash->hash->hash_len;
370
371       /* Process the key material */
372       keymat = silc_calloc(1, sizeof(*keymat));
373       status = silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len,
374                                              keymat);
375       if (status != SILC_SKE_STATUS_OK) {
376         protocol->state = SILC_PROTOCOL_STATE_ERROR;
377         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 300000);
378         silc_ske_free_key_material(keymat);
379         return;
380       }
381       ctx->keymat = keymat;
382
383       /* Send Ok to the other end if we are responder. If we are initiator
384          we have sent this already. */
385       if (ctx->responder == TRUE)
386         silc_ske_end(ctx->ske, ctx->send_packet, context);
387
388       /* Unregister the timeout task since the protocol has ended. 
389          This was the timeout task to be executed if the protocol is
390          not completed fast enough. */
391       if (ctx->timeout_task)
392         silc_task_unregister(client->timeout_queue, ctx->timeout_task);
393
394       /* Protocol has ended, call the final callback */
395       if (protocol->final_callback)
396         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
397       else
398         silc_protocol_free(protocol);
399     }
400     break;
401
402   case SILC_PROTOCOL_STATE_ERROR:
403     /*
404      * Error during protocol
405      */
406     
407     /* Send abort notification */
408     silc_ske_abort(ctx->ske, ctx->ske->status, 
409                    ctx->send_packet, context);
410
411     /* On error the final callback is always called. */
412     if (protocol->final_callback)
413       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
414     else
415       silc_protocol_free(protocol);
416     break;
417
418   case SILC_PROTOCOL_STATE_FAILURE:
419     /*
420      * Received failure from remote.
421      */
422
423     /* Unregister the timeout task since the protocol has ended. 
424        This was the timeout task to be executed if the protocol is
425        not completed fast enough. */
426     if (ctx->timeout_task)
427       silc_task_unregister(client->timeout_queue, ctx->timeout_task);
428
429     /* On error the final callback is always called. */
430     if (protocol->final_callback)
431       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
432     else
433       silc_protocol_free(protocol);
434     break;
435   case SILC_PROTOCOL_STATE_UNKNOWN:
436     break;
437   }
438 }
439
440 /*
441  * Connection Authentication protocol functions
442  */
443
444 static int
445 silc_client_get_public_key_auth(SilcClient client,
446                                 char *filepath,
447                                 unsigned char *auth_data,
448                                 uint32 *auth_data_len,
449                                 SilcSKE ske)
450 {
451   int len;
452   SilcPKCS pkcs;
453   SilcBuffer auth;
454   SilcPublicKey pub_key;
455
456   if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM))
457     if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN))
458       return FALSE;
459
460   silc_pkcs_alloc(pub_key->name, &pkcs);
461   if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
462     silc_pkcs_free(pkcs);
463     silc_pkcs_public_key_free(pub_key);
464     return FALSE;
465   }
466
467   /* Make the authentication data. Protocol says it is HASH plus
468      KE Start Payload. */
469   len = ske->hash_len + ske->start_payload_copy->len;
470   auth = silc_buffer_alloc(len);
471   silc_buffer_pull_tail(auth, len);
472   silc_buffer_format(auth,
473                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
474                      SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
475                                           ske->start_payload_copy->len),
476                      SILC_STR_END);
477
478   if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) {
479     silc_pkcs_free(pkcs);
480     silc_buffer_free(auth);
481     silc_pkcs_public_key_free(pub_key);
482     return TRUE;
483   }
484
485   silc_pkcs_free(pkcs);
486   silc_buffer_free(auth);
487   silc_pkcs_public_key_free(pub_key);
488   return FALSE;
489 }
490
491 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
492 {
493   SilcProtocol protocol = (SilcProtocol)context;
494   SilcClientConnAuthInternalContext *ctx = 
495     (SilcClientConnAuthInternalContext *)protocol->context;
496   SilcClient client = (SilcClient)ctx->client;
497   SilcClientConnection conn = ctx->sock->user_data;
498
499   SILC_LOG_DEBUG(("Start"));
500
501   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
502     protocol->state = SILC_PROTOCOL_STATE_START;
503
504   switch(protocol->state) {
505   case SILC_PROTOCOL_STATE_START:
506     {
507       /* 
508        * Start protocol. We send authentication data to the server
509        * to be authenticated.
510        */
511       SilcBuffer packet;
512       int payload_len = 0;
513       unsigned char *auth_data = NULL;
514       uint32 auth_data_len = 0;
515
516       switch(ctx->auth_meth) {
517       case SILC_AUTH_NONE:
518         /* No authentication required */
519         break;
520
521       case SILC_AUTH_PASSWORD:
522         /* Password authentication */
523         if (ctx->auth_data && ctx->auth_data_len) {
524           auth_data = ctx->auth_data;
525           auth_data_len = ctx->auth_data_len;
526           break;
527         }
528
529         client->ops->say(client, conn, 
530                          "Password authentication required by server %s",
531                          ctx->sock->hostname);
532         auth_data = client->ops->ask_passphrase(client, conn);
533         auth_data_len = strlen(auth_data);
534         break;
535
536       case SILC_AUTH_PUBLIC_KEY:
537         {
538           unsigned char sign[1024];
539
540           /* Public key authentication */
541           silc_client_get_public_key_auth(client, ctx->auth_data,
542                                           sign, &auth_data_len, 
543                                           ctx->ske);
544           auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
545           memcpy(auth_data, sign, auth_data_len);
546           break;
547         }
548       }
549
550       payload_len = 4 + auth_data_len;
551       packet = silc_buffer_alloc(payload_len);
552       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
553       silc_buffer_format(packet,
554                          SILC_STR_UI_SHORT(payload_len),
555                          SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
556                          SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
557                          SILC_STR_END);
558
559       /* Send the packet to server */
560       silc_client_packet_send(client, ctx->sock,
561                               SILC_PACKET_CONNECTION_AUTH,
562                               NULL, 0, NULL, NULL,
563                               packet->data, packet->len, TRUE);
564
565       if (auth_data) {
566         memset(auth_data, 0, auth_data_len);
567         silc_free(auth_data);
568       }
569       silc_buffer_free(packet);
570       
571       /* Next state is end of protocol */
572       protocol->state = SILC_PROTOCOL_STATE_END;
573     }
574     break;
575
576   case SILC_PROTOCOL_STATE_END:
577     {
578       /* 
579        * End protocol. Nothing special to be done here.
580        */
581
582       /* Protocol has ended, call the final callback */
583       if (protocol->final_callback)
584         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
585       else
586         silc_protocol_free(protocol);
587     }
588     break;
589
590   case SILC_PROTOCOL_STATE_ERROR:
591     {
592       /* 
593        * Error. Send notify to remote.
594        */
595       unsigned char error[4];
596
597       SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
598
599       /* Error in protocol. Send FAILURE packet. Although I don't think
600          this could ever happen on client side. */
601       silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
602                               NULL, 0, NULL, NULL, error, 4, TRUE);
603
604       /* On error the final callback is always called. */
605       if (protocol->final_callback)
606         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
607       else
608         silc_protocol_free(protocol);
609     }
610
611   case SILC_PROTOCOL_STATE_FAILURE:
612     /*
613      * Received failure from remote.
614      */
615
616     /* On error the final callback is always called. */
617     if (protocol->final_callback)
618       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
619     else
620       silc_protocol_free(protocol);
621     break;
622
623   case SILC_PROTOCOL_STATE_UNKNOWN:
624     break;
625   }
626 }
627
628 /*
629  * Re-key protocol routines
630  */
631
632 /* Actually takes the new keys into use. */
633
634 static void 
635 silc_client_protocol_rekey_validate(SilcClient client,
636                                     SilcClientRekeyInternalContext *ctx,
637                                     SilcSocketConnection sock,
638                                     SilcSKEKeyMaterial *keymat)
639 {
640   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
641
642   if (ctx->responder == TRUE) {
643     silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, 
644                         keymat->enc_key_len);
645     silc_cipher_set_iv(conn->send_key, keymat->receive_iv);
646     silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, 
647                         keymat->enc_key_len);
648     silc_cipher_set_iv(conn->receive_key, keymat->send_iv);
649   } else {
650     silc_cipher_set_key(conn->send_key, keymat->send_enc_key, 
651                         keymat->enc_key_len);
652     silc_cipher_set_iv(conn->send_key, keymat->send_iv);
653     silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, 
654                         keymat->enc_key_len);
655     silc_cipher_set_iv(conn->receive_key, keymat->receive_iv);
656   }
657
658   silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
659
660   /* Save the current sending encryption key */
661   memset(conn->rekey->send_enc_key, 0, conn->rekey->enc_key_len);
662   silc_free(conn->rekey->send_enc_key);
663   conn->rekey->send_enc_key = 
664     silc_calloc(keymat->enc_key_len / 8,
665                 sizeof(*conn->rekey->send_enc_key));
666   memcpy(conn->rekey->send_enc_key, keymat->send_enc_key, 
667          keymat->enc_key_len / 8);
668   conn->rekey->enc_key_len = keymat->enc_key_len / 8;
669 }
670
671 /* This function actually re-generates (when not using PFS) the keys and
672    takes them into use. */
673
674 void silc_client_protocol_rekey_generate(SilcClient client,
675                                          SilcClientRekeyInternalContext *ctx)
676 {
677   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
678   SilcSKEKeyMaterial *keymat;
679   uint32 key_len = silc_cipher_get_key_len(conn->send_key);
680   uint32 hash_len = conn->hash->hash->hash_len;
681
682   SILC_LOG_DEBUG(("Generating new session keys (no PFS)"));
683
684   /* Generate the new key */
685   keymat = silc_calloc(1, sizeof(*keymat));
686   silc_ske_process_key_material_data(conn->rekey->send_enc_key,
687                                      conn->rekey->enc_key_len,
688                                      16, key_len, hash_len, 
689                                      conn->hash, keymat);
690
691   /* Set the keys into use */
692   silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat);
693
694   silc_ske_free_key_material(keymat);
695 }
696
697 /* This function actually re-generates (with PFS) the keys and
698    takes them into use. */
699
700 void 
701 silc_client_protocol_rekey_generate_pfs(SilcClient client,
702                                         SilcClientRekeyInternalContext *ctx)
703 {
704   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
705   SilcSKEKeyMaterial *keymat;
706   uint32 key_len = silc_cipher_get_key_len(conn->send_key);
707   uint32 hash_len = conn->hash->hash->hash_len;
708   unsigned char *tmpbuf;
709   uint32 klen;
710
711   SILC_LOG_DEBUG(("Generating new session keys (with PFS)"));
712
713   /* Encode KEY to binary data */
714   tmpbuf = silc_mp_mp2bin(ctx->ske->KEY, 0, &klen);
715
716   /* Generate the new key */
717   keymat = silc_calloc(1, sizeof(*keymat));
718   silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len, 
719                                      conn->hash, keymat);
720
721   /* Set the keys into use */
722   silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat);
723
724   memset(tmpbuf, 0, klen);
725   silc_free(tmpbuf);
726   silc_ske_free_key_material(keymat);
727 }
728
729 /* Packet sending callback. This function is provided as packet sending
730    routine to the Key Exchange functions. */
731
732 static void 
733 silc_client_protocol_rekey_send_packet(SilcSKE ske,
734                                        SilcBuffer packet,
735                                        SilcPacketType type,
736                                        void *context)
737 {
738   SilcProtocol protocol = (SilcProtocol)context;
739   SilcClientRekeyInternalContext *ctx = 
740     (SilcClientRekeyInternalContext *)protocol->context;
741   SilcClient client = (SilcClient)ctx->client;
742
743   /* Send the packet immediately */
744   silc_client_packet_send(client, ctx->sock, type, NULL, 0, NULL, NULL,
745                           packet->data, packet->len, TRUE);
746 }
747
748 /* Performs re-key as defined in the SILC protocol specification. */
749
750 SILC_TASK_CALLBACK(silc_client_protocol_rekey)
751 {
752   SilcProtocol protocol = (SilcProtocol)context;
753   SilcClientRekeyInternalContext *ctx = 
754     (SilcClientRekeyInternalContext *)protocol->context;
755   SilcClient client = (SilcClient)ctx->client;
756   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
757   SilcSKEStatus status;
758
759   SILC_LOG_DEBUG(("Start"));
760
761   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
762     protocol->state = SILC_PROTOCOL_STATE_START;
763
764   SILC_LOG_DEBUG(("State=%d", protocol->state));
765
766   switch(protocol->state) {
767   case SILC_PROTOCOL_STATE_START:
768     {
769       /* 
770        * Start protocol.
771        */
772
773       if (ctx->responder == TRUE) {
774         /*
775          * We are receiving party
776          */
777
778         if (ctx->pfs == TRUE) {
779           /* 
780            * Use Perfect Forward Secrecy, ie. negotiate the key material
781            * using the SKE protocol.
782            */
783
784           if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
785             /* Error in protocol */
786             protocol->state = SILC_PROTOCOL_STATE_ERROR;
787             protocol->execute(client->timeout_queue, 0, protocol, fd, 
788                               0, 300000);
789           }
790
791           ctx->ske = silc_ske_alloc();
792           ctx->ske->rng = client->rng;
793           ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
794           silc_ske_get_group_by_number(conn->rekey->ske_group,
795                                        &ctx->ske->prop->group);
796
797           status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer,
798                                               NULL, NULL, NULL, NULL);
799           if (status != SILC_SKE_STATUS_OK) {
800             SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
801                               status));
802             
803             protocol->state = SILC_PROTOCOL_STATE_ERROR;
804             protocol->execute(client->timeout_queue, 0, 
805                               protocol, fd, 0, 300000);
806             return;
807           }
808
809           /* Advance the protocol state */
810           protocol->state++;
811           protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
812         } else {
813           /*
814            * Do normal and simple re-key.
815            */
816
817           /* Send the REKEY_DONE to indicate we will take new keys into use */
818           silc_client_packet_send(client, ctx->sock, 
819                                   SILC_PACKET_REKEY_DONE, 
820                                   NULL, 0, NULL, NULL, NULL, 0, FALSE);
821
822           /* The protocol ends in next stage. */
823           protocol->state = SILC_PROTOCOL_STATE_END;
824         }
825       
826       } else {
827         /*
828          * We are the initiator of this protocol
829          */
830
831         /* Start the re-key by sending the REKEY packet */
832         silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY, 
833                                 NULL, 0, NULL, NULL, NULL, 0, TRUE);
834
835         if (ctx->pfs == TRUE) {
836           /* 
837            * Use Perfect Forward Secrecy, ie. negotiate the key material
838            * using the SKE protocol.
839            */
840           ctx->ske = silc_ske_alloc();
841           ctx->ske->rng = client->rng;
842           ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
843           silc_ske_get_group_by_number(conn->rekey->ske_group,
844                                        &ctx->ske->prop->group);
845
846           status = 
847             silc_ske_initiator_phase_2(ctx->ske, NULL, NULL,
848                                        silc_client_protocol_rekey_send_packet,
849                                        context);
850
851           if (status != SILC_SKE_STATUS_OK) {
852             SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
853                               status));
854             
855             protocol->state = SILC_PROTOCOL_STATE_ERROR;
856             protocol->execute(client->timeout_queue, 0, 
857                               protocol, fd, 0, 300000);
858             return;
859           }
860
861           /* Advance the protocol state */
862           protocol->state++;
863         } else {
864           /*
865            * Do normal and simple re-key.
866            */
867
868           /* The protocol ends in next stage. We have sent the REKEY packet
869              and now we just wait that the responder send REKEY_DONE and
870              the we'll generate the new key, simple. */
871           protocol->state = SILC_PROTOCOL_STATE_END;
872         }
873       }
874     }
875     break;
876
877   case 2:
878     /*
879      * Second state, used only when oding re-key with PFS.
880      */
881     if (ctx->responder == TRUE) {
882       if (ctx->pfs == TRUE) {
883         /*
884          * Send our KE packe to the initiator now that we've processed
885          * the initiator's KE packet.
886          */
887         status = 
888           silc_ske_responder_finish(ctx->ske, NULL, NULL, 
889                                     SILC_SKE_PK_TYPE_SILC,
890                                     silc_client_protocol_rekey_send_packet,
891                                     context);
892
893           if (status != SILC_SKE_STATUS_OK) {
894             SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
895                               status));
896             
897             protocol->state = SILC_PROTOCOL_STATE_ERROR;
898             protocol->execute(client->timeout_queue, 0, 
899                               protocol, fd, 0, 300000);
900             return;
901           }
902       }
903
904     } else {
905       if (ctx->pfs == TRUE) {
906         /*
907          * The packet type must be KE packet
908          */
909         if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
910           /* Error in protocol */
911           protocol->state = SILC_PROTOCOL_STATE_ERROR;
912           protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 300000);
913         }
914         
915         status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer,
916                                            NULL, NULL, NULL, NULL);
917         if (status != SILC_SKE_STATUS_OK) {
918           SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
919                             status));
920           
921           protocol->state = SILC_PROTOCOL_STATE_ERROR;
922           protocol->execute(client->timeout_queue, 0, 
923                             protocol, fd, 0, 300000);
924           return;
925         }
926       }
927     }
928
929     /* Send the REKEY_DONE to indicate we will take new keys into use 
930        now. */ 
931     silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY_DONE, 
932                             NULL, 0, NULL, NULL, NULL, 0, FALSE);
933     
934     /* The protocol ends in next stage. */
935     protocol->state = SILC_PROTOCOL_STATE_END;
936     break;
937
938   case SILC_PROTOCOL_STATE_END:
939     /* 
940      * End protocol
941      */
942
943     if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
944       /* Error in protocol */
945       protocol->state = SILC_PROTOCOL_STATE_ERROR;
946       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
947     }
948
949     if (ctx->responder == FALSE) {
950       if (ctx->pfs == FALSE) {
951         /* Send the REKEY_DONE to indicate we will take new keys into use 
952            now. */ 
953         silc_client_packet_send(client, ctx->sock, 
954                                 SILC_PACKET_REKEY_DONE, 
955                                 NULL, 0, NULL, NULL, NULL, 0, FALSE);
956       }
957     }
958
959     /* Protocol has ended, call the final callback */
960     if (protocol->final_callback)
961       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
962     else
963       silc_protocol_free(protocol);
964     break;
965
966   case SILC_PROTOCOL_STATE_ERROR:
967     /*
968      * Error occured
969      */
970
971     if (ctx->pfs == TRUE) {
972       /* Send abort notification */
973       silc_ske_abort(ctx->ske, ctx->ske->status, 
974                      silc_client_protocol_ke_send_packet,
975                      context);
976     }
977
978     /* On error the final callback is always called. */
979     if (protocol->final_callback)
980       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
981     else
982       silc_protocol_free(protocol);
983     break;
984
985   case SILC_PROTOCOL_STATE_FAILURE:
986     /*
987      * We have received failure from remote
988      */
989
990     /* On error the final callback is always called. */
991     if (protocol->final_callback)
992       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
993     else
994       silc_protocol_free(protocol);
995     break;
996
997   case SILC_PROTOCOL_STATE_UNKNOWN:
998     break;
999   }
1000
1001 }
1002
1003 /* Registers protocols used in client */
1004
1005 void silc_client_protocols_register(void)
1006 {
1007   silc_protocol_register(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
1008                          silc_client_protocol_connection_auth);
1009   silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
1010                          silc_client_protocol_key_exchange);
1011   silc_protocol_register(SILC_PROTOCOL_CLIENT_REKEY,
1012                          silc_client_protocol_rekey);
1013 }
1014
1015 /* Unregisters protocols */
1016
1017 void silc_client_protocols_unregister(void)
1018 {
1019   silc_protocol_unregister(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
1020                            silc_client_protocol_connection_auth);
1021   silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
1022                            silc_client_protocol_key_exchange);
1023   silc_protocol_unregister(SILC_PROTOCOL_CLIENT_REKEY,
1024                            silc_client_protocol_rekey);
1025 }