updates
[silc.git] / lib / silcske / silcske.c
1 /*
2
3   silcske.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2000 - 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 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silcske.h"
24 #include "groups_internal.h"
25
26 /* Structure to hold all SKE callbacks. */
27 struct SilcSKECallbacksStruct {
28   SilcSKESendPacketCb send_packet;
29   SilcSKECb payload_receive;
30   SilcSKEVerifyCb verify_key;
31   SilcSKECb proto_continue;
32   SilcSKECheckVersion check_version;
33   void *context;
34 };
35
36 /* Allocates new SKE object. */
37
38 SilcSKE silc_ske_alloc()
39 {
40   SilcSKE ske;
41
42   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
43
44   ske = silc_calloc(1, sizeof(*ske));
45   ske->status = SILC_SKE_STATUS_OK;
46   ske->users = 1;
47
48   return ske;
49 }
50
51 /* Free's SKE object. */
52
53 void silc_ske_free(SilcSKE ske)
54 {
55   ske->users--;
56   if (ske->users > 0) {
57     SILC_LOG_DEBUG(("Key Exchange set to FREED status"));
58     ske->status = SILC_SKE_STATUS_FREED;
59     return;
60   }
61
62   SILC_LOG_DEBUG(("Freeing Key Exchange object"));
63
64   if (ske) {
65     /* Free start payload */
66     if (ske->start_payload)
67       silc_ske_payload_start_free(ske->start_payload);
68
69     /* Free KE payload */
70     if (ske->ke1_payload)
71       silc_ske_payload_ke_free(ske->ke1_payload);
72
73     /* Free rest */
74     if (ske->prop) {
75       silc_free(ske->prop->group);
76       if (ske->prop->pkcs)
77         silc_pkcs_free(ske->prop->pkcs);
78       if (ske->prop->cipher)
79         silc_cipher_free(ske->prop->cipher);
80       if (ske->prop->hash)
81         silc_hash_free(ske->prop->hash);
82       if (ske->prop->hmac)
83         silc_hmac_free(ske->prop->hmac);
84       silc_free(ske->prop);
85     }
86     if (ske->start_payload_copy)
87       silc_buffer_free(ske->start_payload_copy);
88     if (ske->x) {
89       silc_mp_uninit(ske->x);
90       silc_free(ske->x);
91     }
92     if (ske->KEY) {
93       silc_mp_uninit(ske->KEY);
94       silc_free(ske->KEY);
95     }
96     silc_free(ske->hash);
97     silc_free(ske->callbacks);
98     silc_free(ske);
99   }
100 }
101
102 /* Sets the callback functions for the SKE session. 
103
104    The `send_packet' callback is a function that sends the packet to
105    network. The SKE library will call it at any time packet needs to
106    be sent to the remote host. 
107
108    The `payload_receive' callback is called when the remote host's Key
109    Exchange Start Payload has been processed.  The payload is saved
110    to ske->start_payload if the application would need it.  The application
111    must also provide the payload to the next state of the SKE.
112
113    The `verify_key' callback is called to verify the received public key
114    or certificate.  The verification process is most likely asynchronous.
115    That is why the application must call the completion callback when the
116    verification process has been completed. The library then calls the user
117    callback (`proto_continue'), if it is provided to indicate that the SKE
118    protocol may continue. 
119    
120    The `proto_continue' callback is called to indicate that it is
121    safe to continue the execution of the SKE protocol after executing
122    an asynchronous operation, such as calling the `verify_key' callback
123    function, which is asynchronous. The application should check the
124    ske->status in this function to check whether it is Ok to continue
125    the execution of the protocol.
126
127    The `check_version' callback is called to verify the remote host's
128    version. The application may check its own version against the remote
129    host's version and determine whether supporting the remote host
130    is possible. 
131
132    The `context' is passed as argument to all of the above callback
133    functions. */
134
135 void silc_ske_set_callbacks(SilcSKE ske,
136                             SilcSKESendPacketCb send_packet,
137                             SilcSKECb payload_receive,
138                             SilcSKEVerifyCb verify_key,
139                             SilcSKECb proto_continue,
140                             SilcSKECheckVersion check_version,
141                             void *context)
142 {
143   if (ske->callbacks)
144     silc_free(ske->callbacks);
145   ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
146   ske->callbacks->send_packet = send_packet;
147   ske->callbacks->payload_receive = payload_receive;
148   ske->callbacks->verify_key = verify_key;
149   ske->callbacks->proto_continue = proto_continue;
150   ske->callbacks->check_version = check_version;
151   ske->callbacks->context = context;
152 }
153
154 /* Starts the SILC Key Exchange protocol for initiator. The connection
155    to the remote end must be established before calling this function
156    and the connecting socket must be sent as argument. This function
157    creates the Key Exchange Start Payload which includes all our
158    configured security properties. This payload is then sent to the
159    remote end for further processing. This payload must be sent as
160    argument to the function, however, it must not be encoded
161    already, it is done by this function. The caller must not free
162    the `start_payload' since the SKE library will save it.
163
164    The packet sending is done by calling a callback function. Caller
165    must provide a routine to send the packet. */
166
167 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
168                                        SilcSocketConnection sock,
169                                        SilcSKEStartPayload *start_payload)
170 {
171   SilcSKEStatus status = SILC_SKE_STATUS_OK;
172   SilcBuffer payload_buf;
173
174   SILC_LOG_DEBUG(("Start"));
175
176   ske->sock = sock;
177   ske->rng = rng;
178
179   /* Encode the payload */
180   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
181   if (status != SILC_SKE_STATUS_OK)
182     return status;
183
184   /* Take a copy of the payload buffer for future use. It is used to
185      compute the HASH value. */
186   ske->start_payload_copy = silc_buffer_copy(payload_buf);
187   ske->start_payload = start_payload;
188
189   /* Send the packet. */
190   if (ske->callbacks->send_packet)
191     (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
192                                    ske->callbacks->context);
193
194   silc_buffer_free(payload_buf);
195
196   return status;
197 }
198
199 /* Function called after ske_initiator_start fuction. This receives
200    the remote ends Key Exchange Start payload which includes the
201    security properties selected by the responder from our payload
202    sent in the silc_ske_initiator_start function. */
203
204 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
205                                          SilcBuffer start_payload)
206 {
207   SilcSKEStatus status = SILC_SKE_STATUS_OK;
208   SilcSKEStartPayload *payload;
209   SilcSKESecurityProperties prop;
210   SilcSKEDiffieHellmanGroup group;
211
212   SILC_LOG_DEBUG(("Start"));
213
214   /* Decode the payload */
215   status = silc_ske_payload_start_decode(ske, start_payload, &payload);
216   if (status != SILC_SKE_STATUS_OK) {
217     ske->status = status;
218     silc_ske_payload_start_free(ske->start_payload);
219     return status;
220   }
221
222   /* Check that the cookie is returned unmodified */
223   if (memcmp(ske->start_payload->cookie, payload->cookie,
224              ske->start_payload->cookie_len)) {
225     SILC_LOG_DEBUG(("Responder modified our cookie and it must not do it"));
226     ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
227     silc_ske_payload_start_free(ske->start_payload);
228     return status;
229   }
230
231   /* Check version string */
232   if (ske->callbacks->check_version) {
233     status = ske->callbacks->check_version(ske, payload->version, 
234                                            payload->version_len,
235                                            ske->callbacks->context);
236     if (status != SILC_SKE_STATUS_OK) {
237       ske->status = status;
238       silc_ske_payload_start_free(ske->start_payload);
239       return status;
240     }
241   }
242
243   /* Free our KE Start Payload context, we don't need it anymore. */
244   silc_ske_payload_start_free(ske->start_payload);
245
246   /* Take the selected security properties into use while doing
247      the key exchange. This is used only while doing the key 
248      exchange. The same data is returned to upper levels by calling
249      the callback function. */
250   ske->prop = prop = silc_calloc(1, sizeof(*prop));
251   prop->flags = payload->flags;
252   status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
253   if (status != SILC_SKE_STATUS_OK)
254     goto err;
255
256   prop->group = group;
257
258   if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
259     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
260     goto err;
261   }
262
263   if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
264     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
265     goto err;
266   }
267
268   if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
269     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
270     goto err;
271   }
272
273   if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
274     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
275     goto err;
276   }
277
278   /* Save remote's KE Start Payload */
279   ske->start_payload = payload;
280
281   /* Return the received payload by calling the callback function. */
282   if (ske->callbacks->payload_receive)
283     (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
284
285   return status;
286
287  err:
288   if (payload)
289     silc_ske_payload_start_free(payload);
290
291   silc_free(group);
292
293   if (prop->pkcs)
294     silc_pkcs_free(prop->pkcs);
295   if (prop->cipher)
296     silc_cipher_free(prop->cipher);
297   if (prop->hash)
298     silc_hash_free(prop->hash);
299   if (prop->hmac)
300     silc_hmac_free(prop->hmac);
301   silc_free(prop);
302   ske->prop = NULL;
303
304   if (status == SILC_SKE_STATUS_OK)
305     return SILC_SKE_STATUS_ERROR;
306
307   ske->status = status;
308   return status;
309 }
310
311 /* This function creates random number x, such that 1 < x < q and 
312    computes e = g ^ x mod p and sends the result to the remote end in 
313    Key Exchange Payload. */
314
315 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
316                                          SilcPublicKey public_key,
317                                          SilcPrivateKey private_key)
318 {
319   SilcSKEStatus status = SILC_SKE_STATUS_OK;
320   SilcBuffer payload_buf;
321   SilcMPInt *x;
322   SilcSKEKEPayload *payload;
323   uint32 pk_len;
324
325   SILC_LOG_DEBUG(("Start"));
326
327   /* Create the random number x, 1 < x < q. */
328   x = silc_calloc(1, sizeof(*x));
329   silc_mp_init(x);
330   status = 
331     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
332                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
333                         x);
334   if (status != SILC_SKE_STATUS_OK) {
335     silc_mp_uninit(x);
336     silc_free(x);
337     ske->status = status;
338     return status;
339   }
340
341   /* Encode the result to Key Exchange Payload. */
342
343   payload = silc_calloc(1, sizeof(*payload));
344   ske->ke1_payload = payload;
345
346   SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
347
348   /* Do the Diffie Hellman computation, e = g ^ x mod p */
349   silc_mp_init(&payload->x);
350   silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x, 
351                   &ske->prop->group->group);
352
353   /* Get public key */
354   if (public_key) {
355     payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
356     if (!payload->pk_data) {
357       silc_mp_uninit(x);
358       silc_free(x);
359       silc_mp_uninit(&payload->x);
360       silc_free(payload);
361       ske->status = SILC_SKE_STATUS_OK;
362       return ske->status;
363     }
364     payload->pk_len = pk_len;
365   }
366   payload->pk_type = SILC_SKE_PK_TYPE_SILC;
367
368   /* Compute signature data if we are doing mutual authentication */
369   if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
370     unsigned char hash[32], sign[1024];
371     uint32 hash_len, sign_len;
372
373     SILC_LOG_DEBUG(("We are doing mutual authentication"));
374     SILC_LOG_DEBUG(("Computing HASH_i value"));
375
376     /* Compute the hash value */
377     memset(hash, 0, sizeof(hash));
378     silc_ske_make_hash(ske, hash, &hash_len, TRUE);
379
380     SILC_LOG_DEBUG(("Signing HASH_i value"));
381     
382     /* Sign the hash value */
383     silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
384                                    private_key->prv_len);
385     silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
386     payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
387     memcpy(payload->sign_data, sign, sign_len);
388     memset(sign, 0, sizeof(sign));
389     payload->sign_len = sign_len;
390   }
391
392   status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
393   if (status != SILC_SKE_STATUS_OK) {
394     silc_mp_uninit(x);
395     silc_free(x);
396     silc_mp_uninit(&payload->x);
397     silc_free(payload->pk_data);
398     silc_free(payload);
399     ske->status = status;
400     return status;
401   }
402
403   ske->x = x;
404
405   /* Send the packet. */
406   if (ske->callbacks->send_packet)
407     (*ske->callbacks->send_packet)(ske, payload_buf, 
408                                    SILC_PACKET_KEY_EXCHANGE_1, 
409                                    ske->callbacks->context);
410
411   silc_buffer_free(payload_buf);
412
413   return status;
414 }
415
416 /* An initiator finish final callback that is called to indicate that
417    the SKE protocol may continue. */
418
419 static void silc_ske_initiator_finish_final(SilcSKE ske,
420                                             SilcSKEStatus status,
421                                             void *context)
422 {
423   SilcSKEKEPayload *payload;
424   unsigned char hash[32];
425   uint32 hash_len;
426   SilcPublicKey public_key = NULL;
427
428   /* If the SKE was freed during the async call then free it really now,
429      otherwise just decrement the reference counter. */
430   if (ske->status == SILC_SKE_STATUS_FREED) {
431     silc_ske_free(ske);
432     return;
433   }
434
435   /* If the caller returns PENDING status SKE library will assume that
436      the caller will re-call this callback when it is not anymore in
437      PENDING status. */
438   if (status == SILC_SKE_STATUS_PENDING)
439     return;
440
441   ske->users--;
442   payload = ske->ke2_payload;
443
444   /* If the status is an error then the public key that was verified
445      by the caller is not authentic. */
446   if (status != SILC_SKE_STATUS_OK) {
447     ske->status = status;
448     if (ske->callbacks->proto_continue)
449       ske->callbacks->proto_continue(ske, ske->callbacks->context);
450     return;
451   }
452
453   if (payload->pk_data) {
454     /* Decode the public key */
455     if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, 
456                                      &public_key)) {
457       status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
458       if (ske->callbacks->proto_continue)
459         ske->callbacks->proto_continue(ske, ske->callbacks->context);
460       return;
461     }
462
463     SILC_LOG_DEBUG(("Public key is authentic"));
464
465     /* Compute the hash value */
466     status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
467     if (status != SILC_SKE_STATUS_OK)
468       goto err;
469
470     ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
471     memcpy(ske->hash, hash, hash_len);
472     ske->hash_len = hash_len;
473
474     SILC_LOG_DEBUG(("Verifying signature (HASH)"));
475
476     /* Verify signature */
477     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
478     if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data, 
479                          payload->sign_len, hash, hash_len) == FALSE) {
480       
481       SILC_LOG_DEBUG(("Signature don't match"));
482       
483       status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
484       goto err;
485     }
486
487     SILC_LOG_DEBUG(("Signature is Ok"));
488     
489     silc_pkcs_public_key_free(public_key);
490     memset(hash, 'F', hash_len);
491   }
492
493   ske->status = SILC_SKE_STATUS_OK;
494
495   /* Call the callback. The caller may now continue the SKE protocol. */
496   if (ske->callbacks->proto_continue)
497     ske->callbacks->proto_continue(ske, ske->callbacks->context);
498
499   return;
500
501  err:
502   memset(hash, 'F', sizeof(hash));
503   silc_ske_payload_ke_free(payload);
504   ske->ke2_payload = NULL;
505
506   silc_mp_uninit(ske->KEY);
507   silc_free(ske->KEY);
508   ske->KEY = NULL;
509
510   if (public_key)
511     silc_pkcs_public_key_free(public_key);
512
513   if (ske->hash) {
514     memset(ske->hash, 'F', hash_len);
515     silc_free(ske->hash);
516     ske->hash = NULL;
517   }
518
519   if (status == SILC_SKE_STATUS_OK)
520     ske->status = SILC_SKE_STATUS_ERROR;
521
522   ske->status = status;
523
524   /* Call the callback. */
525   if (ske->callbacks->proto_continue)
526     ske->callbacks->proto_continue(ske, ske->callbacks->context);
527 }
528
529 /* Receives Key Exchange Payload from responder consisting responders
530    public key, f, and signature. This function verifies the public key,
531    computes the secret shared key and verifies the signature. 
532
533    The `callback' will be called to indicate that the caller may
534    continue with the SKE protocol.  The caller must not continue
535    before the SKE libary has called that callback.  If this function
536    returns an error the callback will not be called.  It is called
537    if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
538    However, note that when the library calls the callback the ske->status
539    may be error.
540
541    This calls the `verify_key' callback to verify the received public
542    key or certificate. If the `verify_key' is provided then the remote
543    must send public key and it is considered to be an error if remote 
544    does not send its public key. If caller is performing a re-key with
545    SKE then the `verify_key' is usually not provided when it is not also
546    required for the remote to send its public key. */
547
548 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
549                                         SilcBuffer ke_payload)
550 {
551   SilcSKEStatus status = SILC_SKE_STATUS_OK;
552   SilcSKEKEPayload *payload;
553   SilcMPInt *KEY;
554
555   SILC_LOG_DEBUG(("Start"));
556
557   /* Decode the payload */
558   status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
559   if (status != SILC_SKE_STATUS_OK) {
560     ske->status = status;
561     return status;
562   }
563   ske->ke2_payload = payload;
564
565   if (!payload->pk_data && ske->callbacks->verify_key) {
566     SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
567                     "even though we require it"));
568     ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
569     goto err;
570   }
571
572   SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
573
574   /* Compute the shared secret key */
575   KEY = silc_calloc(1, sizeof(*KEY));
576   silc_mp_init(KEY);
577   silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
578   ske->KEY = KEY;
579
580   if (payload->pk_data && ske->callbacks->verify_key) {
581     SILC_LOG_DEBUG(("Verifying public key"));
582     
583     ske->users++;
584     (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
585                                  payload->pk_type, ske->callbacks->context,
586                                  silc_ske_initiator_finish_final, NULL);
587     
588     /* We will continue to the final state after the public key has
589        been verified by the caller. */
590     return SILC_SKE_STATUS_PENDING;
591   }
592
593   /* Continue to final state */
594   ske->users++;
595   silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
596
597   return SILC_SKE_STATUS_OK;
598
599  err:
600   silc_ske_payload_ke_free(payload);
601   ske->ke2_payload = NULL;
602
603   silc_mp_uninit(ske->KEY);
604   silc_free(ske->KEY);
605   ske->KEY = NULL;
606
607   if (status == SILC_SKE_STATUS_OK)
608     return SILC_SKE_STATUS_ERROR;
609
610   ske->status = status;
611   return status;
612 }
613
614 /* Starts Key Exchange protocol for responder. Responder receives
615    Key Exchange Start Payload from initiator consisting of all the
616    security properties the initiator supports. This function decodes
617    the payload and parses the payload further and selects the right 
618    security properties. */
619
620 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
621                                        SilcSocketConnection sock,
622                                        char *version,
623                                        SilcBuffer start_payload,
624                                        bool mutual_auth)
625 {
626   SilcSKEStatus status = SILC_SKE_STATUS_OK;
627   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
628
629   SILC_LOG_DEBUG(("Start"));
630
631   ske->sock = sock;
632   ske->rng = rng;
633
634   /* Decode the payload */
635   status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
636   if (status != SILC_SKE_STATUS_OK) {
637     ske->status = status;
638     return status;
639   }
640
641   /* Take a copy of the payload buffer for future use. It is used to
642      compute the HASH value. */
643   ske->start_payload_copy = silc_buffer_copy(start_payload);
644
645   /* Force the mutual authentication flag if we want to do it. */
646   if (mutual_auth) {
647     SILC_LOG_DEBUG(("Force mutual authentication"));
648     remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
649   }
650
651   /* Parse and select the security properties from the payload */
652   payload = silc_calloc(1, sizeof(*payload));
653   status = silc_ske_select_security_properties(ske, version,
654                                                payload, remote_payload);
655   if (status != SILC_SKE_STATUS_OK)
656     goto err;
657
658   ske->start_payload = payload;
659
660   /* Call the callback function. */
661   if (ske->callbacks->payload_receive)
662     (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
663
664   silc_ske_payload_start_free(remote_payload);
665
666   return status;
667
668  err:
669   if (remote_payload)
670     silc_ske_payload_start_free(remote_payload);
671   if (payload)
672     silc_free(payload);
673
674   if (status == SILC_SKE_STATUS_OK)
675     return SILC_SKE_STATUS_ERROR;
676
677   ske->status = status;
678   return status;
679 }
680
681 /* The selected security properties from the initiator payload is now 
682    encoded into Key Exchange Start Payload and sent to the initiator. */
683
684 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
685                                          SilcSKEStartPayload *start_payload)
686 {
687   SilcSKEStatus status = SILC_SKE_STATUS_OK;
688   SilcBuffer payload_buf;
689   SilcSKESecurityProperties prop;
690   SilcSKEDiffieHellmanGroup group = NULL;
691
692   SILC_LOG_DEBUG(("Start"));
693
694   /* Allocate security properties from the payload. These are allocated
695      only for this negotiation and will be free'd after KE is over. */
696   ske->prop = prop = silc_calloc(1, sizeof(*prop));
697   prop->flags = start_payload->flags;
698   status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
699   if (status != SILC_SKE_STATUS_OK)
700     goto err;
701
702   prop->group = group;
703
704   if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
705                       &prop->pkcs) == FALSE) {
706     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
707     goto err;
708   }
709
710   if (silc_cipher_alloc(start_payload->enc_alg_list, 
711                         &prop->cipher) == FALSE) {
712     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
713     goto err;
714   }
715
716   if (silc_hash_alloc(start_payload->hash_alg_list,
717                       &prop->hash) == FALSE) {
718     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
719     goto err;
720   }
721
722   if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
723                       &prop->hmac) == FALSE) {
724     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
725     goto err;
726   }
727
728   /* Encode the payload */
729   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
730   if (status != SILC_SKE_STATUS_OK)
731     goto err;
732
733   /* Send the packet. */
734   if (ske->callbacks->send_packet)
735     (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
736                                    ske->callbacks->context);
737
738   silc_buffer_free(payload_buf);
739
740   return status;
741
742  err:
743   if (group)
744     silc_free(group);
745
746   if (prop->pkcs)
747     silc_pkcs_free(prop->pkcs);
748   if (prop->cipher)
749     silc_cipher_free(prop->cipher);
750   if (prop->hash)
751     silc_hash_free(prop->hash);
752   if (prop->hmac)
753     silc_hmac_free(prop->hmac);
754   silc_free(prop);
755   ske->prop = NULL;
756
757   if (status == SILC_SKE_STATUS_OK)
758     return SILC_SKE_STATUS_ERROR;
759
760   ske->status = status;
761   return status;
762 }
763
764 /* An responder phase 2 final callback that is called to indicate that
765    the SKE protocol may continue. */
766
767 static void silc_ske_responder_phase2_final(SilcSKE ske,
768                                             SilcSKEStatus status,
769                                             void *context)
770 {
771   SilcSKEKEPayload *recv_payload, *send_payload;
772   SilcMPInt *x;
773
774   /* If the SKE was freed during the async call then free it really now,
775      otherwise just decrement the reference counter. */
776   if (ske->status == SILC_SKE_STATUS_FREED) {
777     silc_ske_free(ske);
778     return;
779   }
780
781   /* If the caller returns PENDING status SKE library will assume that
782      the caller will re-call this callback when it is not anymore in
783      PENDING status. */
784   if (status == SILC_SKE_STATUS_PENDING)
785     return;
786
787   ske->users--;
788   recv_payload = ske->ke1_payload;
789
790   /* If the status is an error then the public key that was verified
791      by the caller is not authentic. */
792   if (status != SILC_SKE_STATUS_OK) {
793     ske->status = status;
794     if (ske->callbacks->proto_continue)
795       ske->callbacks->proto_continue(ske, ske->callbacks->context);
796     return;
797   }
798
799   /* The public key verification was performed only if the Mutual
800      Authentication flag is set. */
801   if (ske->start_payload && 
802       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
803     SilcPublicKey public_key = NULL;
804     unsigned char hash[32];
805     uint32 hash_len;
806
807     /* Decode the public key */
808     if (!silc_pkcs_public_key_decode(recv_payload->pk_data, 
809                                      recv_payload->pk_len, 
810                                      &public_key)) {
811       ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
812       if (ske->callbacks->proto_continue)
813         ske->callbacks->proto_continue(ske, ske->callbacks->context);
814       return;
815     }
816
817     SILC_LOG_DEBUG(("Public key is authentic"));
818
819     /* Compute the hash value */
820     status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
821     if (status != SILC_SKE_STATUS_OK) {
822       ske->status = status;
823       if (ske->callbacks->proto_continue)
824         ske->callbacks->proto_continue(ske, ske->callbacks->context);
825       return;
826     }
827
828     SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
829     
830     /* Verify signature */
831     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
832     if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, 
833                          recv_payload->sign_len, hash, hash_len) == FALSE) {
834       
835       SILC_LOG_DEBUG(("Signature don't match"));
836       
837       ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
838       if (ske->callbacks->proto_continue)
839         ske->callbacks->proto_continue(ske, ske->callbacks->context);
840       return;
841     }
842     
843     SILC_LOG_DEBUG(("Signature is Ok"));
844     
845     silc_pkcs_public_key_free(public_key);
846     memset(hash, 'F', hash_len);
847   }
848
849   /* Create the random number x, 1 < x < q. */
850   x = silc_calloc(1, sizeof(*x));
851   silc_mp_init(x);
852   status = 
853     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
854                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
855                         x);
856   if (status != SILC_SKE_STATUS_OK) {
857     silc_mp_uninit(x);
858     silc_free(x);
859     ske->status = status;
860     if (ske->callbacks->proto_continue)
861       ske->callbacks->proto_continue(ske, ske->callbacks->context);
862     return;
863   }
864
865   /* Save the results for later processing */
866   send_payload = silc_calloc(1, sizeof(*send_payload));
867   ske->x = x;
868   ske->ke2_payload = send_payload;
869
870   SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
871
872   /* Do the Diffie Hellman computation, f = g ^ x mod p */
873   silc_mp_init(&send_payload->x);
874   silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x, 
875                   &ske->prop->group->group);
876   
877   /* Call the callback. The caller may now continue with the SKE protocol. */
878   ske->status = SILC_SKE_STATUS_OK;
879   if (ske->callbacks->proto_continue)
880     ske->callbacks->proto_continue(ske, ske->callbacks->context);
881 }
882
883 /* This function receives the Key Exchange Payload from the initiator.
884    This also performs the mutual authentication if required. Then, this 
885    function first generated a random number x, such that 1 < x < q
886    and computes f = g ^ x mod p. This then puts the result f to a Key
887    Exchange Payload. 
888
889    The `callback' will be called to indicate that the caller may
890    continue with the SKE protocol.  The caller must not continue
891    before the SKE libary has called that callback.  If this function
892    returns an error the callback will not be called.  It is called
893    if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
894    However, note that when the library calls the callback the ske->status
895    may be error.
896
897    This calls the `verify_key' callback to verify the received public
898    key or certificate if the Mutual Authentication flag is set. If the
899    `verify_key' is provided then the remote must send public key and it
900    is considered to be an error if remote does not send its public key. */
901
902 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
903                                          SilcBuffer ke_payload)
904 {
905   SilcSKEStatus status = SILC_SKE_STATUS_OK;
906   SilcSKEKEPayload *recv_payload;
907
908   SILC_LOG_DEBUG(("Start"));
909
910   /* Decode Key Exchange Payload */
911   status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
912   if (status != SILC_SKE_STATUS_OK) {
913     ske->status = status;
914     return status;
915   }
916
917   ske->ke1_payload = recv_payload;
918
919   /* Verify the received public key and verify the signature if we are
920      doing mutual authentication. */
921   if (ske->start_payload && 
922       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
923
924     SILC_LOG_DEBUG(("We are doing mutual authentication"));
925     
926     if (!recv_payload->pk_data && ske->callbacks->verify_key) {
927       SILC_LOG_DEBUG(("Remote end did not send its public key (or "
928                       "certificate), even though we require it"));
929       ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
930       return status;
931     }
932
933     if (recv_payload->pk_data && ske->callbacks->verify_key) {
934       SILC_LOG_DEBUG(("Verifying public key"));
935
936       ske->users++;
937       (*ske->callbacks->verify_key)(ske, recv_payload->pk_data, 
938                                     recv_payload->pk_len,
939                                     recv_payload->pk_type, 
940                                     ske->callbacks->context,
941                                     silc_ske_responder_phase2_final, NULL);
942
943       /* We will continue to the final state after the public key has
944          been verified by the caller. */
945       return SILC_SKE_STATUS_PENDING;
946     }
947   }
948
949   /* Continue to final state */
950   ske->users++;
951   silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
952
953   return SILC_SKE_STATUS_OK;
954 }
955
956 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
957    value to be signed and sent to the other end. This then encodes Key
958    Exchange Payload and sends it to the other end. */
959
960 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
961                                         SilcPublicKey public_key,
962                                         SilcPrivateKey private_key,
963                                         SilcSKEPKType pk_type)
964 {
965   SilcSKEStatus status = SILC_SKE_STATUS_OK;
966   SilcBuffer payload_buf;
967   SilcMPInt *KEY;
968   unsigned char hash[32], sign[1024], *pk;
969   uint32 hash_len, sign_len, pk_len;
970
971   SILC_LOG_DEBUG(("Start"));
972
973   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
974
975   /* Compute the shared secret key */
976   KEY = silc_calloc(1, sizeof(*KEY));
977   silc_mp_init(KEY);
978   silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x, 
979                   &ske->prop->group->group);
980   ske->KEY = KEY;
981
982   if (public_key && private_key) {
983     SILC_LOG_DEBUG(("Getting public key"));
984     
985     /* Get the public key */
986     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
987     if (!pk) {
988       status = SILC_SKE_STATUS_ERROR;
989       goto err;
990     }
991     ske->ke2_payload->pk_data = pk;
992     ske->ke2_payload->pk_len = pk_len;
993     
994     SILC_LOG_DEBUG(("Computing HASH value"));
995     
996     /* Compute the hash value */
997     memset(hash, 0, sizeof(hash));
998     status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
999     if (status != SILC_SKE_STATUS_OK)
1000       goto err;
1001
1002     ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
1003     memcpy(ske->hash, hash, hash_len);
1004     ske->hash_len = hash_len;
1005     
1006     SILC_LOG_DEBUG(("Signing HASH value"));
1007     
1008     /* Sign the hash value */
1009     silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
1010                                    private_key->prv_len);
1011     silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
1012     ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
1013     memcpy(ske->ke2_payload->sign_data, sign, sign_len);
1014     memset(sign, 0, sizeof(sign));
1015     ske->ke2_payload->sign_len = sign_len;
1016   }
1017   ske->ke2_payload->pk_type = pk_type;
1018
1019   /* Encode the Key Exchange Payload */
1020   status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1021                                       &payload_buf);
1022   if (status != SILC_SKE_STATUS_OK)
1023     goto err;
1024
1025   /* Send the packet. */
1026   if (ske->callbacks->send_packet)
1027     (*ske->callbacks->send_packet)(ske, payload_buf, 
1028                                    SILC_PACKET_KEY_EXCHANGE_2,
1029                                    ske->callbacks->context);
1030
1031   silc_buffer_free(payload_buf);
1032
1033   return status;
1034
1035  err:
1036   silc_mp_uninit(ske->KEY);
1037   silc_free(ske->KEY);
1038   ske->KEY = NULL;
1039   silc_ske_payload_ke_free(ske->ke2_payload);
1040
1041   if (status == SILC_SKE_STATUS_OK)
1042     return SILC_SKE_STATUS_ERROR;
1043
1044   ske->status = status;
1045   return status;
1046 }
1047
1048 /* The Key Exchange protocol is ended by calling this function. This
1049    must not be called until the keys are processed like the protocol
1050    defines. This function is for both initiator and responder. */
1051
1052 SilcSKEStatus silc_ske_end(SilcSKE ske)
1053 {
1054   SilcBuffer packet;
1055
1056   SILC_LOG_DEBUG(("Start"));
1057
1058   packet = silc_buffer_alloc(4);
1059   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1060   silc_buffer_format(packet,
1061                      SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1062                      SILC_STR_END);
1063
1064   if (ske->callbacks->send_packet)
1065     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS, 
1066                                    ske->callbacks->context);
1067
1068   silc_buffer_free(packet);
1069
1070   return SILC_SKE_STATUS_OK;
1071 }
1072
1073 /* Aborts the Key Exchange protocol. This is called if error occurs
1074    while performing the protocol. The status argument is the error
1075    status and it is sent to the remote end. */
1076
1077 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1078 {
1079   SilcBuffer packet;
1080
1081   SILC_LOG_DEBUG(("Start"));
1082
1083   packet = silc_buffer_alloc(4);
1084   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1085   silc_buffer_format(packet,
1086                      SILC_STR_UI_INT((uint32)status),
1087                      SILC_STR_END);
1088
1089   if (ske->callbacks->send_packet)
1090     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE, 
1091                                    ske->callbacks->context);
1092
1093   silc_buffer_free(packet);
1094
1095   return SILC_SKE_STATUS_OK;
1096 }
1097
1098 /* Assembles security properties to Key Exchange Start Payload to be
1099    sent to the remote end. This checks system wide (SILC system, that is)
1100    settings and chooses from those. However, if other properties
1101    should be used this function is easy to replace by another function,
1102    as, this function is called by the caller of the protocol and not
1103    by the protocol itself. */
1104
1105 SilcSKEStatus 
1106 silc_ske_assemble_security_properties(SilcSKE ske,
1107                                       unsigned char flags,
1108                                       char *version,
1109                                       SilcSKEStartPayload **return_payload)
1110 {
1111   SilcSKEStartPayload *rp;
1112   int i;
1113
1114   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1115
1116   rp = silc_calloc(1, sizeof(*rp));
1117
1118   /* Set flags */
1119   rp->flags = flags;
1120
1121   /* Set random cookie */
1122   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1123   for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1124     rp->cookie[i] = silc_rng_get_byte(ske->rng);
1125   rp->cookie_len = SILC_SKE_COOKIE_LEN;
1126
1127   /* Put version */
1128   rp->version = strdup(version);
1129   rp->version_len = strlen(version);
1130
1131   /* Get supported Key Exhange groups */
1132   rp->ke_grp_list = silc_ske_get_supported_groups();
1133   rp->ke_grp_len = strlen(rp->ke_grp_list);
1134
1135   /* Get supported PKCS algorithms */
1136   rp->pkcs_alg_list = silc_pkcs_get_supported();
1137   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1138
1139   /* Get supported encryption algorithms */
1140   rp->enc_alg_list = silc_cipher_get_supported();
1141   rp->enc_alg_len = strlen(rp->enc_alg_list);
1142
1143   /* Get supported hash algorithms */
1144   rp->hash_alg_list = silc_hash_get_supported();
1145   rp->hash_alg_len = strlen(rp->hash_alg_list);
1146
1147   /* Get supported HMACs */
1148   rp->hmac_alg_list = silc_hmac_get_supported();
1149   rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1150
1151   /* XXX */
1152   /* Get supported compression algorithms */
1153   rp->comp_alg_list = strdup("");
1154   rp->comp_alg_len = 0;
1155
1156   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1157     2 + rp->version_len +
1158     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
1159     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
1160     2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1161
1162   *return_payload = rp;
1163
1164   return SILC_SKE_STATUS_OK;
1165 }
1166
1167 /* Selects the supported security properties from the remote end's Key 
1168    Exchange Start Payload. */
1169
1170 SilcSKEStatus 
1171 silc_ske_select_security_properties(SilcSKE ske,
1172                                     char *version,
1173                                     SilcSKEStartPayload *payload,
1174                                     SilcSKEStartPayload *remote_payload)
1175 {
1176   SilcSKEStatus status;
1177   SilcSKEStartPayload *rp;
1178   char *cp;
1179   int len;
1180
1181   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1182
1183   rp = remote_payload;
1184
1185   /* Check version string */
1186   if (ske->callbacks->check_version) {
1187     status = ske->callbacks->check_version(ske, rp->version, 
1188                                            rp->version_len,
1189                                            ske->callbacks->context);
1190     if (status != SILC_SKE_STATUS_OK) {
1191       ske->status = status;
1192       return status;
1193     }
1194   }
1195
1196   /* Flags are returned unchanged. */
1197   payload->flags = rp->flags;
1198
1199   /* Take cookie, we must return it to sender unmodified. */
1200   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1201   payload->cookie_len = SILC_SKE_COOKIE_LEN;
1202   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1203
1204   /* Put our version to our reply */
1205   payload->version = strdup(version);
1206   payload->version_len = strlen(version);
1207
1208   /* Get supported Key Exchange groups */
1209   cp = rp->ke_grp_list;
1210   if (cp && strchr(cp, ',')) {
1211     while(cp) {
1212       char *item;
1213
1214       len = strcspn(cp, ",");
1215       item = silc_calloc(len + 1, sizeof(char));
1216       memcpy(item, cp, len);
1217
1218       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1219
1220       if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1221         SILC_LOG_DEBUG(("Found KE group `%s'", item));
1222
1223         payload->ke_grp_len = len;
1224         payload->ke_grp_list = item;
1225         break;
1226       }
1227
1228       cp += len;
1229       if (strlen(cp) == 0)
1230         cp = NULL;
1231       else
1232         cp++;
1233
1234       if (item)
1235         silc_free(item);
1236     }
1237
1238     if (!payload->ke_grp_len && !payload->ke_grp_list) {
1239       SILC_LOG_DEBUG(("Could not find supported KE group"));
1240       silc_free(payload);
1241       return SILC_SKE_STATUS_UNKNOWN_GROUP;
1242     }
1243   } else {
1244
1245     if (!rp->ke_grp_len) {
1246       SILC_LOG_DEBUG(("KE group not defined in payload"));
1247       silc_free(payload);
1248       return SILC_SKE_STATUS_BAD_PAYLOAD;
1249     }
1250
1251     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1252     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1253
1254     payload->ke_grp_len = rp->ke_grp_len;
1255     payload->ke_grp_list = strdup(rp->ke_grp_list);
1256   }
1257
1258   /* Get supported PKCS algorithms */
1259   cp = rp->pkcs_alg_list;
1260   if (cp && strchr(cp, ',')) {
1261     while(cp) {
1262       char *item;
1263
1264       len = strcspn(cp, ",");
1265       item = silc_calloc(len + 1, sizeof(char));
1266       memcpy(item, cp, len);
1267
1268       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1269
1270       if (silc_pkcs_is_supported(item) == TRUE) {
1271         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1272
1273         payload->pkcs_alg_len = len;
1274         payload->pkcs_alg_list = item;
1275         break;
1276       }
1277
1278       cp += len;
1279       if (strlen(cp) == 0)
1280         cp = NULL;
1281       else
1282         cp++;
1283
1284       if (item)
1285         silc_free(item);
1286     }
1287
1288     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1289       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1290       silc_free(payload->ke_grp_list);
1291       silc_free(payload);
1292       return SILC_SKE_STATUS_UNKNOWN_PKCS;
1293     }
1294   } else {
1295
1296     if (!rp->pkcs_alg_len) {
1297       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1298       silc_free(payload->ke_grp_list);
1299       silc_free(payload);
1300       return SILC_SKE_STATUS_BAD_PAYLOAD;
1301     }
1302
1303     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1304     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1305
1306     payload->pkcs_alg_len = rp->pkcs_alg_len;
1307     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1308   }
1309
1310   /* Get supported encryption algorithms */
1311   cp = rp->enc_alg_list;
1312   if (cp && strchr(cp, ',')) {
1313     while(cp) {
1314       char *item;
1315
1316       len = strcspn(cp, ",");
1317       item = silc_calloc(len + 1, sizeof(char));
1318       memcpy(item, cp, len);
1319
1320       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1321
1322       if (silc_cipher_is_supported(item) == TRUE) {
1323         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1324
1325         payload->enc_alg_len = len;
1326         payload->enc_alg_list = item;
1327         break;
1328       }
1329
1330       cp += len;
1331       if (strlen(cp) == 0)
1332         cp = NULL;
1333       else
1334         cp++;
1335
1336       if (item)
1337         silc_free(item);
1338     }
1339
1340     if (!payload->enc_alg_len && !payload->enc_alg_list) {
1341       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1342       silc_free(payload->ke_grp_list);
1343       silc_free(payload->pkcs_alg_list);
1344       silc_free(payload);
1345       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1346     }
1347   } else {
1348
1349     if (!rp->enc_alg_len) {
1350       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1351       silc_free(payload->ke_grp_list);
1352       silc_free(payload->pkcs_alg_list);
1353       silc_free(payload);
1354       return SILC_SKE_STATUS_BAD_PAYLOAD;
1355     }
1356
1357     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1358                     rp->enc_alg_list));
1359
1360     payload->enc_alg_len = rp->enc_alg_len;
1361     payload->enc_alg_list = strdup(rp->enc_alg_list);
1362   }
1363
1364   /* Get supported hash algorithms */
1365   cp = rp->hash_alg_list;
1366   if (cp && strchr(cp, ',')) {
1367     while(cp) {
1368       char *item;
1369
1370       len = strcspn(cp, ",");
1371       item = silc_calloc(len + 1, sizeof(char));
1372       memcpy(item, cp, len);
1373
1374       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1375
1376       if (silc_hash_is_supported(item) == TRUE) {
1377         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1378
1379         payload->hash_alg_len = len;
1380         payload->hash_alg_list = item;
1381         break;
1382       }
1383
1384       cp += len;
1385       if (strlen(cp) == 0)
1386         cp = NULL;
1387       else
1388         cp++;
1389
1390       if (item)
1391         silc_free(item);
1392     }
1393
1394     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1395       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1396       silc_free(payload->ke_grp_list);
1397       silc_free(payload->pkcs_alg_list);
1398       silc_free(payload->enc_alg_list);
1399       silc_free(payload);
1400       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1401     }
1402   } else {
1403
1404     if (!rp->hash_alg_len) {
1405       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1406       silc_free(payload->ke_grp_list);
1407       silc_free(payload->pkcs_alg_list);
1408       silc_free(payload->enc_alg_list);
1409       silc_free(payload);
1410       return SILC_SKE_STATUS_BAD_PAYLOAD;
1411     }
1412
1413     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1414                     rp->hash_alg_list));
1415
1416     payload->hash_alg_len = rp->hash_alg_len;
1417     payload->hash_alg_list = strdup(rp->hash_alg_list);
1418   }
1419
1420   /* Get supported HMACs */
1421   cp = rp->hmac_alg_list;
1422   if (cp && strchr(cp, ',')) {
1423     while(cp) {
1424       char *item;
1425
1426       len = strcspn(cp, ",");
1427       item = silc_calloc(len + 1, sizeof(char));
1428       memcpy(item, cp, len);
1429
1430       SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1431
1432       if (silc_hmac_is_supported(item) == TRUE) {
1433         SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1434
1435         payload->hmac_alg_len = len;
1436         payload->hmac_alg_list = item;
1437         break;
1438       }
1439
1440       cp += len;
1441       if (strlen(cp) == 0)
1442         cp = NULL;
1443       else
1444         cp++;
1445
1446       if (item)
1447         silc_free(item);
1448     }
1449
1450     if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1451       SILC_LOG_DEBUG(("Could not find supported HMAC"));
1452       silc_free(payload->ke_grp_list);
1453       silc_free(payload->pkcs_alg_list);
1454       silc_free(payload->enc_alg_list);
1455       silc_free(payload->hash_alg_list);
1456       silc_free(payload);
1457       return SILC_SKE_STATUS_UNKNOWN_HMAC;
1458     }
1459   } else {
1460
1461     if (!rp->hmac_alg_len) {
1462       SILC_LOG_DEBUG(("HMAC not defined in payload"));
1463       silc_free(payload->ke_grp_list);
1464       silc_free(payload->pkcs_alg_list);
1465       silc_free(payload->enc_alg_list);
1466       silc_free(payload->hash_alg_list);
1467       silc_free(payload);
1468       return SILC_SKE_STATUS_BAD_PAYLOAD;
1469     }
1470
1471     SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1472                     rp->hmac_alg_list));
1473
1474     payload->hmac_alg_len = rp->hmac_alg_len;
1475     payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1476   }
1477
1478 #if 0
1479   /* Get supported compression algorithms */
1480   cp = rp->hash_alg_list;
1481   if (cp && strchr(cp, ',')) {
1482     while(cp) {
1483       char *item;
1484
1485       len = strcspn(cp, ",");
1486       item = silc_calloc(len + 1, sizeof(char));
1487       memcpy(item, cp, len);
1488
1489       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1490
1491       if (silc_hash_is_supported(item) == TRUE) {
1492         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1493
1494         payload->hash_alg_len = len;
1495         payload->hash_alg_list = item;
1496         break;
1497       }
1498
1499       cp += len;
1500       if (strlen(cp) == 0)
1501         cp = NULL;
1502       else
1503         cp++;
1504
1505       if (item)
1506         silc_free(item);
1507     }
1508
1509     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1510       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1511       silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1512       silc_free(payload->ke_grp_list);
1513       silc_free(payload->pkcs_alg_list);
1514       silc_free(payload->enc_alg_list);
1515       silc_free(payload);
1516       return;
1517     }
1518   } else {
1519
1520   }
1521 #endif
1522
1523   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1524     2 + payload->version_len + 
1525     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1526     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1527     2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1528
1529   return SILC_SKE_STATUS_OK;
1530 }
1531
1532 /* Creates random number such that 1 < rnd < n and at most length
1533    of len bits. The rnd sent as argument must be initialized. */
1534
1535 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, 
1536                                   uint32 len, 
1537                                   SilcMPInt *rnd)
1538 {
1539   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1540   unsigned char *string;
1541
1542   SILC_LOG_DEBUG(("Creating random number"));
1543
1544   /* Get the random number as string */
1545   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1546   if (!string)
1547     return SILC_SKE_STATUS_ERROR;
1548
1549   /* Decode the string into a MP integer */
1550   silc_mp_bin2mp(string, (len / 8), rnd);
1551   silc_mp_mod_2exp(rnd, rnd, len);
1552
1553   /* Checks */
1554   if (silc_mp_cmp_ui(rnd, 1) < 0)
1555     status = SILC_SKE_STATUS_ERROR;
1556
1557   if (silc_mp_cmp(rnd, n) >= 0)
1558     status = SILC_SKE_STATUS_ERROR;
1559
1560   memset(string, 'F', (len / 8));
1561   silc_free(string);
1562
1563   return status;
1564 }
1565
1566 /* Creates a hash value HASH as defined in the SKE protocol. If the
1567    `initiator' is TRUE then this function is used to create the HASH_i
1568    hash value defined in the protocol. If it is FALSE then this is used
1569    to create the HASH value defined by the protocol. */
1570
1571 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1572                                  unsigned char *return_hash,
1573                                  uint32 *return_hash_len,
1574                                  int initiator)
1575 {
1576   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1577   SilcBuffer buf;
1578   unsigned char *e, *f, *KEY;
1579   uint32 e_len, f_len, KEY_len;
1580   int ret;
1581
1582   SILC_LOG_DEBUG(("Start"));
1583
1584   if (initiator == FALSE) {
1585     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1586     f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1587     KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1588     
1589     /* Format the buffer used to compute the hash value */
1590     /* XXX Backward support for 0.6.1 */
1591     if (ske->backward_version == 1) {
1592       SILC_LOG_DEBUG(("*********** Using old KE payload"));
1593       buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1594                               ske->ke2_payload->pk_len + e_len + 
1595                               f_len + KEY_len);
1596       silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1597
1598       ret = 
1599         silc_buffer_format(buf,
1600                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1601                                                 ske->start_payload_copy->len),
1602                            SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1603                                                 ske->ke2_payload->pk_len),
1604                            SILC_STR_UI_XNSTRING(e, e_len),
1605                            SILC_STR_UI_XNSTRING(f, f_len),
1606                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
1607                            SILC_STR_END);
1608     } else {
1609       /* Initiator is not required to send its public key */
1610       SILC_LOG_DEBUG(("*********** Using new KE payload"));
1611       buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1612                               ske->ke2_payload->pk_len + 
1613                               ske->ke1_payload->pk_len + 
1614                               e_len + f_len + KEY_len);
1615       silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1616
1617       if (!ske->ke1_payload->pk_data) {
1618         ret = 
1619           silc_buffer_format(buf,
1620                              SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1621                                                   data,
1622                                                   ske->start_payload_copy->
1623                                                   len),
1624                              SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1625                                                   ske->ke2_payload->pk_len),
1626                              SILC_STR_UI_XNSTRING(e, e_len),
1627                              SILC_STR_UI_XNSTRING(f, f_len),
1628                              SILC_STR_UI_XNSTRING(KEY, KEY_len),
1629                              SILC_STR_END);
1630       } else {
1631         ret = 
1632           silc_buffer_format(buf,
1633                              SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1634                                                   data,
1635                                                   ske->start_payload_copy->
1636                                                   len),
1637                              SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1638                                                   ske->ke2_payload->pk_len),
1639                              SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
1640                                                   ske->ke1_payload->pk_len),
1641                              SILC_STR_UI_XNSTRING(e, e_len),
1642                              SILC_STR_UI_XNSTRING(f, f_len),
1643                              SILC_STR_UI_XNSTRING(KEY, KEY_len),
1644                              SILC_STR_END);
1645       }
1646     }
1647     if (ret == -1) {
1648       silc_buffer_free(buf);
1649       memset(e, 0, e_len);
1650       memset(f, 0, f_len);
1651       memset(KEY, 0, KEY_len);
1652       silc_free(e);
1653       silc_free(f);
1654       silc_free(KEY);
1655       return SILC_SKE_STATUS_ERROR;
1656     }
1657
1658     memset(e, 0, e_len);
1659     memset(f, 0, f_len);
1660     memset(KEY, 0, KEY_len);
1661     silc_free(e);
1662     silc_free(f);
1663     silc_free(KEY);
1664   } else {
1665     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1666
1667     buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1668                             ske->ke1_payload->pk_len + e_len);
1669     silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1670     
1671     /* Format the buffer used to compute the hash value */
1672     ret = 
1673       silc_buffer_format(buf,
1674                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1675                                               ske->start_payload_copy->len),
1676                          SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
1677                                               ske->ke1_payload->pk_len),
1678                          SILC_STR_UI_XNSTRING(e, e_len),
1679                          SILC_STR_END);
1680     if (ret == -1) {
1681       silc_buffer_free(buf);
1682       memset(e, 0, e_len);
1683       silc_free(e);
1684       return SILC_SKE_STATUS_ERROR;
1685     }
1686
1687     memset(e, 0, e_len);
1688     silc_free(e);
1689   }
1690
1691   /* Make the hash */
1692   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1693   *return_hash_len = ske->prop->hash->hash->hash_len;
1694
1695   if (initiator == FALSE) {
1696     SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1697   } else {
1698     SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1699   }
1700
1701   silc_buffer_free(buf);
1702
1703   return status;
1704 }
1705
1706 /* Processes the provided key material `data' as the SILC protocol 
1707    specification defines. */
1708
1709 SilcSKEStatus 
1710 silc_ske_process_key_material_data(unsigned char *data,
1711                                    uint32 data_len,
1712                                    uint32 req_iv_len,
1713                                    uint32 req_enc_key_len,
1714                                    uint32 req_hmac_key_len,
1715                                    SilcHash hash,
1716                                    SilcSKEKeyMaterial *key)
1717 {
1718   SilcBuffer buf;
1719   unsigned char hashd[32];
1720   uint32 hash_len = req_hmac_key_len;
1721   uint32 enc_key_len = req_enc_key_len / 8;
1722
1723   SILC_LOG_DEBUG(("Start"));
1724
1725   if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1726     return SILC_SKE_STATUS_ERROR;
1727
1728   buf = silc_buffer_alloc(1 + data_len);
1729   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1730   silc_buffer_format(buf,
1731                      SILC_STR_UI_CHAR(0),
1732                      SILC_STR_UI_XNSTRING(data, data_len),
1733                      SILC_STR_END);
1734
1735   /* Take IVs */
1736   memset(hashd, 0, sizeof(hashd));
1737   buf->data[0] = 0;
1738   silc_hash_make(hash, buf->data, buf->len, hashd);
1739   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1740   memcpy(key->send_iv, hashd, req_iv_len);
1741   memset(hashd, 0, sizeof(hashd));
1742   buf->data[0] = 1;
1743   silc_hash_make(hash, buf->data, buf->len, hashd);
1744   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1745   memcpy(key->receive_iv, hashd, req_iv_len);
1746   key->iv_len = req_iv_len;
1747
1748   /* Take the encryption keys. If requested key size is more than
1749      the size of hash length we will distribute more key material
1750      as protocol defines. */
1751   buf->data[0] = 2;
1752   if (enc_key_len > hash_len) {
1753     SilcBuffer dist;
1754     unsigned char k1[32], k2[32], k3[32];
1755     unsigned char *dtmp;
1756     
1757     /* XXX */
1758     if (enc_key_len > (3 * hash_len))
1759       return SILC_SKE_STATUS_ERROR;
1760     
1761     /* Take first round */
1762     memset(k1, 0, sizeof(k1));
1763     silc_hash_make(hash, buf->data, buf->len, k1);
1764     
1765     /* Take second round */
1766     dist = silc_buffer_alloc(data_len + hash_len);
1767     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1768     silc_buffer_format(dist,
1769                        SILC_STR_UI_XNSTRING(data, data_len),
1770                        SILC_STR_UI_XNSTRING(k1, hash_len),
1771                        SILC_STR_END);
1772     memset(k2, 0, sizeof(k2));
1773     silc_hash_make(hash, dist->data, dist->len, k2);
1774
1775     /* Take third round */
1776     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1777     silc_buffer_pull_tail(dist, hash_len);
1778     silc_buffer_pull(dist, data_len + hash_len);
1779     silc_buffer_format(dist,
1780                        SILC_STR_UI_XNSTRING(k2, hash_len),
1781                        SILC_STR_END);
1782     silc_buffer_push(dist, data_len + hash_len);
1783     memset(k3, 0, sizeof(k3));
1784     silc_hash_make(hash, dist->data, dist->len, k3);
1785
1786     /* Then, save the keys */
1787     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1788     memcpy(dtmp, k1, hash_len);
1789     memcpy(dtmp + hash_len, k2, hash_len);
1790     memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1791
1792     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1793     memcpy(key->send_enc_key, dtmp, enc_key_len);
1794     key->enc_key_len = req_enc_key_len;
1795
1796     memset(dtmp, 0, (3 * hash_len));
1797     memset(k1, 0, sizeof(k1));
1798     memset(k2, 0, sizeof(k2));
1799     memset(k3, 0, sizeof(k3));
1800     silc_free(dtmp);
1801     silc_buffer_free(dist);
1802   } else {
1803     /* Take normal hash as key */
1804     memset(hashd, 0, sizeof(hashd));
1805     silc_hash_make(hash, buf->data, buf->len, hashd);
1806     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1807     memcpy(key->send_enc_key, hashd, enc_key_len);
1808     key->enc_key_len = req_enc_key_len;
1809   }
1810
1811   buf->data[0] = 3;
1812   if (enc_key_len > hash_len) {
1813     SilcBuffer dist;
1814     unsigned char k1[32], k2[32], k3[32];
1815     unsigned char *dtmp;
1816     
1817     /* XXX */
1818     if (enc_key_len > (3 * hash_len))
1819       return SILC_SKE_STATUS_ERROR;
1820     
1821     /* Take first round */
1822     memset(k1, 0, sizeof(k1));
1823     silc_hash_make(hash, buf->data, buf->len, k1);
1824     
1825     /* Take second round */
1826     dist = silc_buffer_alloc(data_len + hash_len);
1827     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1828     silc_buffer_format(dist,
1829                        SILC_STR_UI_XNSTRING(data, data_len),
1830                        SILC_STR_UI_XNSTRING(k1, hash_len),
1831                        SILC_STR_END);
1832     memset(k2, 0, sizeof(k2));
1833     silc_hash_make(hash, dist->data, dist->len, k2);
1834     
1835     /* Take third round */
1836     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1837     silc_buffer_pull_tail(dist, hash_len);
1838     silc_buffer_pull(dist, data_len + hash_len);
1839     silc_buffer_format(dist,
1840                        SILC_STR_UI_XNSTRING(k2, hash_len),
1841                        SILC_STR_END);
1842     silc_buffer_push(dist, data_len + hash_len);
1843     memset(k3, 0, sizeof(k3));
1844     silc_hash_make(hash, dist->data, dist->len, k3);
1845
1846     /* Then, save the keys */
1847     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1848     memcpy(dtmp, k1, hash_len);
1849     memcpy(dtmp + hash_len, k2, hash_len);
1850     memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1851
1852     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1853     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1854     key->enc_key_len = req_enc_key_len;
1855
1856     memset(dtmp, 0, (3 * hash_len));
1857     memset(k1, 0, sizeof(k1));
1858     memset(k2, 0, sizeof(k2));
1859     memset(k3, 0, sizeof(k3));
1860     silc_free(dtmp);
1861     silc_buffer_free(dist);
1862   } else {
1863     /* Take normal hash as key */
1864     memset(hashd, 0, sizeof(hashd));
1865     silc_hash_make(hash, buf->data, buf->len, hashd);
1866     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1867     memcpy(key->receive_enc_key, hashd, enc_key_len);
1868     key->enc_key_len = req_enc_key_len;
1869   }
1870
1871   /* Take HMAC keys */
1872   memset(hashd, 0, sizeof(hashd));
1873   buf->data[0] = 4;
1874   silc_hash_make(hash, buf->data, buf->len, hashd);
1875   key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1876   memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
1877   memset(hashd, 0, sizeof(hashd));
1878   buf->data[0] = 5;
1879   silc_hash_make(hash, buf->data, buf->len, hashd);
1880   key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1881   memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
1882   key->hmac_key_len = req_hmac_key_len;
1883   memset(hashd, 0, sizeof(hashd));
1884
1885   silc_buffer_free(buf);
1886
1887   return SILC_SKE_STATUS_OK;
1888 }
1889
1890 /* Processes negotiated key material as protocol specifies. This returns
1891    the actual keys to be used in the SILC. */
1892
1893 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1894                                             uint32 req_iv_len,
1895                                             uint32 req_enc_key_len,
1896                                             uint32 req_hmac_key_len,
1897                                             SilcSKEKeyMaterial *key)
1898 {
1899   SilcSKEStatus status;
1900   SilcBuffer buf;
1901   unsigned char *tmpbuf;
1902   uint32 klen;
1903
1904   /* Encode KEY to binary data */
1905   tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1906
1907   buf = silc_buffer_alloc(klen + ske->hash_len);
1908   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1909   silc_buffer_format(buf,
1910                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
1911                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1912                      SILC_STR_END);
1913
1914   /* Process the key material */
1915   status = silc_ske_process_key_material_data(buf->data, buf->len,
1916                                               req_iv_len, req_enc_key_len,
1917                                               req_hmac_key_len, 
1918                                               ske->prop->hash, key);
1919
1920   memset(tmpbuf, 0, klen);
1921   silc_free(tmpbuf);
1922   silc_buffer_free(buf);
1923
1924   return status;
1925 }
1926
1927 /* Free key material structure */
1928
1929 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1930 {
1931   if (!key)
1932     return;
1933
1934   if (key->send_iv)
1935     silc_free(key->send_iv);
1936   if (key->receive_iv)
1937     silc_free(key->receive_iv);
1938   if (key->send_enc_key) {
1939     memset(key->send_enc_key, 0, key->enc_key_len / 8);
1940     silc_free(key->send_enc_key);
1941   }
1942   if (key->receive_enc_key) {
1943     memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1944     silc_free(key->receive_enc_key);
1945   }
1946   if (key->send_hmac_key) {
1947     memset(key->send_hmac_key, 0, key->hmac_key_len);
1948     silc_free(key->send_hmac_key);
1949   }
1950   if (key->receive_hmac_key) {
1951     memset(key->receive_hmac_key, 0, key->hmac_key_len);
1952     silc_free(key->receive_hmac_key);
1953   }
1954   silc_free(key);
1955 }
1956
1957 const char *silc_ske_status_string[] = 
1958 {
1959   /* Official */
1960   "Ok",
1961   "Unkown error occurred",
1962   "Bad payload in packet",
1963   "Unsupported group",
1964   "Unsupported cipher",
1965   "Unsupported PKCS",
1966   "Unsupported hash function",
1967   "Unsupported HMAC",
1968   "Unsupported public key (or certificate)",
1969   "Incorrect signature",
1970   "Bad or unsupported version",
1971   "Invalid cookie",
1972
1973   /* Other errors */
1974   "Pending",
1975   "Remote did not provide public key",
1976   "Key exchange protocol is not active",
1977   "Bad reserved field in packet",
1978   "Bad payload length in packet",
1979   "Incorrect hash",
1980
1981   NULL
1982 };
1983
1984 /* Maps status to readable string and returns the string. If string is not
1985    found and empty character string ("") is returned. */
1986
1987 const char *silc_ske_map_status(SilcSKEStatus status)
1988 {
1989   int i;
1990
1991   for (i = 0; silc_ske_status_string[i]; i++)
1992     if (status == i)
1993       return silc_ske_status_string[i];
1994
1995   return "";
1996 }