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