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_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     if (ske->hash)
98       silc_free(ske->hash);
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_get_group_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_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   return status;
666
667  err:
668   if (remote_payload)
669     silc_ske_payload_start_free(remote_payload);
670   if (payload)
671     silc_free(payload);
672
673   if (status == SILC_SKE_STATUS_OK)
674     return SILC_SKE_STATUS_ERROR;
675
676   ske->status = status;
677   return status;
678 }
679
680 /* The selected security properties from the initiator payload is now 
681    encoded into Key Exchange Start Payload and sent to the initiator. */
682
683 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
684                                          SilcSKEStartPayload *start_payload)
685 {
686   SilcSKEStatus status = SILC_SKE_STATUS_OK;
687   SilcBuffer payload_buf;
688   SilcSKESecurityProperties prop;
689   SilcSKEDiffieHellmanGroup group = NULL;
690
691   SILC_LOG_DEBUG(("Start"));
692
693   /* Allocate security properties from the payload. These are allocated
694      only for this negotiation and will be free'd after KE is over. */
695   ske->prop = prop = silc_calloc(1, sizeof(*prop));
696   prop->flags = start_payload->flags;
697   status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
698   if (status != SILC_SKE_STATUS_OK)
699     goto err;
700
701   prop->group = group;
702
703   if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
704                       &prop->pkcs) == FALSE) {
705     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
706     goto err;
707   }
708
709   if (silc_cipher_alloc(start_payload->enc_alg_list, 
710                         &prop->cipher) == FALSE) {
711     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
712     goto err;
713   }
714
715   if (silc_hash_alloc(start_payload->hash_alg_list,
716                       &prop->hash) == FALSE) {
717     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
718     goto err;
719   }
720
721   if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
722                       &prop->hmac) == FALSE) {
723     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
724     goto err;
725   }
726
727   /* Encode the payload */
728   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
729   if (status != SILC_SKE_STATUS_OK)
730     goto err;
731
732   /* Send the packet. */
733   if (ske->callbacks->send_packet)
734     (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
735                                    ske->callbacks->context);
736
737   silc_buffer_free(payload_buf);
738
739   return status;
740
741  err:
742   if (group)
743     silc_free(group);
744
745   if (prop->pkcs)
746     silc_pkcs_free(prop->pkcs);
747   if (prop->cipher)
748     silc_cipher_free(prop->cipher);
749   if (prop->hash)
750     silc_hash_free(prop->hash);
751   if (prop->hmac)
752     silc_hmac_free(prop->hmac);
753   silc_free(prop);
754   ske->prop = NULL;
755
756   if (status == SILC_SKE_STATUS_OK)
757     return SILC_SKE_STATUS_ERROR;
758
759   ske->status = status;
760   return status;
761 }
762
763 /* An responder phase 2 final callback that is called to indicate that
764    the SKE protocol may continue. */
765
766 static void silc_ske_responder_phase2_final(SilcSKE ske,
767                                             SilcSKEStatus status,
768                                             void *context)
769 {
770   SilcSKEKEPayload *recv_payload, *send_payload;
771   SilcMPInt *x;
772
773   /* If the SKE was freed during the async call then free it really now,
774      otherwise just decrement the reference counter. */
775   if (ske->status == SILC_SKE_STATUS_FREED) {
776     silc_ske_free(ske);
777     return;
778   }
779
780   /* If the caller returns PENDING status SKE library will assume that
781      the caller will re-call this callback when it is not anymore in
782      PENDING status. */
783   if (status == SILC_SKE_STATUS_PENDING)
784     return;
785
786   ske->users--;
787   recv_payload = ske->ke1_payload;
788
789   /* If the status is an error then the public key that was verified
790      by the caller is not authentic. */
791   if (status != SILC_SKE_STATUS_OK) {
792     ske->status = status;
793     if (ske->callbacks->proto_continue)
794       ske->callbacks->proto_continue(ske, ske->callbacks->context);
795     return;
796   }
797
798   /* The public key verification was performed only if the Mutual
799      Authentication flag is set. */
800   if (ske->start_payload && 
801       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
802     SilcPublicKey public_key = NULL;
803     unsigned char hash[32];
804     uint32 hash_len;
805
806     /* Decode the public key */
807     if (!silc_pkcs_public_key_decode(recv_payload->pk_data, 
808                                      recv_payload->pk_len, 
809                                      &public_key)) {
810       ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
811       if (ske->callbacks->proto_continue)
812         ske->callbacks->proto_continue(ske, ske->callbacks->context);
813       return;
814     }
815
816     SILC_LOG_DEBUG(("Public key is authentic"));
817
818     /* Compute the hash value */
819     status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
820     if (status != SILC_SKE_STATUS_OK) {
821       ske->status = status;
822       if (ske->callbacks->proto_continue)
823         ske->callbacks->proto_continue(ske, ske->callbacks->context);
824       return;
825     }
826
827     SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
828     
829     /* Verify signature */
830     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
831     if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, 
832                          recv_payload->sign_len, hash, hash_len) == FALSE) {
833       
834       SILC_LOG_DEBUG(("Signature don't match"));
835       
836       ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
837       if (ske->callbacks->proto_continue)
838         ske->callbacks->proto_continue(ske, ske->callbacks->context);
839       return;
840     }
841     
842     SILC_LOG_DEBUG(("Signature is Ok"));
843     
844     silc_pkcs_public_key_free(public_key);
845     memset(hash, 'F', hash_len);
846   }
847
848   /* Create the random number x, 1 < x < q. */
849   x = silc_calloc(1, sizeof(*x));
850   silc_mp_init(x);
851   status = 
852     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
853                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
854                         x);
855   if (status != SILC_SKE_STATUS_OK) {
856     silc_mp_uninit(x);
857     silc_free(x);
858     ske->status = status;
859     if (ske->callbacks->proto_continue)
860       ske->callbacks->proto_continue(ske, ske->callbacks->context);
861     return;
862   }
863
864   /* Save the results for later processing */
865   send_payload = silc_calloc(1, sizeof(*send_payload));
866   ske->x = x;
867   ske->ke2_payload = send_payload;
868
869   SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
870
871   /* Do the Diffie Hellman computation, f = g ^ x mod p */
872   silc_mp_init(&send_payload->x);
873   silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x, 
874                   &ske->prop->group->group);
875   
876   /* Call the callback. The caller may now continue with the SKE protocol. */
877   ske->status = SILC_SKE_STATUS_OK;
878   if (ske->callbacks->proto_continue)
879     ske->callbacks->proto_continue(ske, ske->callbacks->context);
880 }
881
882 /* This function receives the Key Exchange Payload from the initiator.
883    This also performs the mutual authentication if required. Then, this 
884    function first generated a random number x, such that 1 < x < q
885    and computes f = g ^ x mod p. This then puts the result f to a Key
886    Exchange Payload. 
887
888    The `callback' will be called to indicate that the caller may
889    continue with the SKE protocol.  The caller must not continue
890    before the SKE libary has called that callback.  If this function
891    returns an error the callback will not be called.  It is called
892    if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
893    However, note that when the library calls the callback the ske->status
894    may be error.
895
896    This calls the `verify_key' callback to verify the received public
897    key or certificate if the Mutual Authentication flag is set. If the
898    `verify_key' is provided then the remote must send public key and it
899    is considered to be an error if remote does not send its public key. */
900
901 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
902                                          SilcBuffer ke_payload)
903 {
904   SilcSKEStatus status = SILC_SKE_STATUS_OK;
905   SilcSKEKEPayload *recv_payload;
906
907   SILC_LOG_DEBUG(("Start"));
908
909   /* Decode Key Exchange Payload */
910   status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
911   if (status != SILC_SKE_STATUS_OK) {
912     ske->status = status;
913     return status;
914   }
915
916   ske->ke1_payload = recv_payload;
917
918   /* Verify the received public key and verify the signature if we are
919      doing mutual authentication. */
920   if (ske->start_payload && 
921       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
922
923     SILC_LOG_DEBUG(("We are doing mutual authentication"));
924     
925     if (!recv_payload->pk_data && ske->callbacks->verify_key) {
926       SILC_LOG_DEBUG(("Remote end did not send its public key (or "
927                       "certificate), even though we require it"));
928       ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
929       return status;
930     }
931
932     if (recv_payload->pk_data && ske->callbacks->verify_key) {
933       SILC_LOG_DEBUG(("Verifying public key"));
934
935       ske->users++;
936       (*ske->callbacks->verify_key)(ske, recv_payload->pk_data, 
937                                     recv_payload->pk_len,
938                                     recv_payload->pk_type, 
939                                     ske->callbacks->context,
940                                     silc_ske_responder_phase2_final, NULL);
941
942       /* We will continue to the final state after the public key has
943          been verified by the caller. */
944       return SILC_SKE_STATUS_PENDING;
945     }
946   }
947
948   /* Continue to final state */
949   ske->users++;
950   silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
951
952   return SILC_SKE_STATUS_OK;
953 }
954
955 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
956    value to be signed and sent to the other end. This then encodes Key
957    Exchange Payload and sends it to the other end. */
958
959 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
960                                         SilcPublicKey public_key,
961                                         SilcPrivateKey private_key,
962                                         SilcSKEPKType pk_type)
963 {
964   SilcSKEStatus status = SILC_SKE_STATUS_OK;
965   SilcBuffer payload_buf;
966   SilcMPInt *KEY;
967   unsigned char hash[32], sign[1024], *pk;
968   uint32 hash_len, sign_len, pk_len;
969
970   SILC_LOG_DEBUG(("Start"));
971
972   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
973
974   /* Compute the shared secret key */
975   KEY = silc_calloc(1, sizeof(*KEY));
976   silc_mp_init(KEY);
977   silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x, 
978                   &ske->prop->group->group);
979   ske->KEY = KEY;
980
981   if (public_key && private_key) {
982     SILC_LOG_DEBUG(("Getting public key"));
983     
984     /* Get the public key */
985     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
986     if (!pk) {
987       status = SILC_SKE_STATUS_ERROR;
988       goto err;
989     }
990     ske->ke2_payload->pk_data = pk;
991     ske->ke2_payload->pk_len = pk_len;
992     
993     SILC_LOG_DEBUG(("Computing HASH value"));
994     
995     /* Compute the hash value */
996     memset(hash, 0, sizeof(hash));
997     status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
998     if (status != SILC_SKE_STATUS_OK)
999       goto err;
1000
1001     ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
1002     memcpy(ske->hash, hash, hash_len);
1003     ske->hash_len = hash_len;
1004     
1005     SILC_LOG_DEBUG(("Signing HASH value"));
1006     
1007     /* Sign the hash value */
1008     silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
1009                                    private_key->prv_len);
1010     silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
1011     ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
1012     memcpy(ske->ke2_payload->sign_data, sign, sign_len);
1013     memset(sign, 0, sizeof(sign));
1014     ske->ke2_payload->sign_len = sign_len;
1015   }
1016   ske->ke2_payload->pk_type = pk_type;
1017
1018   /* Encode the Key Exchange Payload */
1019   status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1020                                       &payload_buf);
1021   if (status != SILC_SKE_STATUS_OK)
1022     goto err;
1023
1024   /* Send the packet. */
1025   if (ske->callbacks->send_packet)
1026     (*ske->callbacks->send_packet)(ske, payload_buf, 
1027                                    SILC_PACKET_KEY_EXCHANGE_2,
1028                                    ske->callbacks->context);
1029
1030   silc_buffer_free(payload_buf);
1031
1032   return status;
1033
1034  err:
1035   silc_mp_uninit(ske->KEY);
1036   silc_free(ske->KEY);
1037   ske->KEY = NULL;
1038   silc_ske_payload_ke_free(ske->ke2_payload);
1039
1040   if (status == SILC_SKE_STATUS_OK)
1041     return SILC_SKE_STATUS_ERROR;
1042
1043   ske->status = status;
1044   return status;
1045 }
1046
1047 /* The Key Exchange protocol is ended by calling this function. This
1048    must not be called until the keys are processed like the protocol
1049    defines. This function is for both initiator and responder. */
1050
1051 SilcSKEStatus silc_ske_end(SilcSKE ske)
1052 {
1053   SilcBuffer packet;
1054
1055   SILC_LOG_DEBUG(("Start"));
1056
1057   packet = silc_buffer_alloc(4);
1058   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1059   silc_buffer_format(packet,
1060                      SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1061                      SILC_STR_END);
1062
1063   if (ske->callbacks->send_packet)
1064     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS, 
1065                                    ske->callbacks->context);
1066
1067   silc_buffer_free(packet);
1068
1069   return SILC_SKE_STATUS_OK;
1070 }
1071
1072 /* Aborts the Key Exchange protocol. This is called if error occurs
1073    while performing the protocol. The status argument is the error
1074    status and it is sent to the remote end. */
1075
1076 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1077 {
1078   SilcBuffer packet;
1079
1080   SILC_LOG_DEBUG(("Start"));
1081
1082   packet = silc_buffer_alloc(4);
1083   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1084   silc_buffer_format(packet,
1085                      SILC_STR_UI_INT((uint32)status),
1086                      SILC_STR_END);
1087
1088   if (ske->callbacks->send_packet)
1089     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE, 
1090                                    ske->callbacks->context);
1091
1092   silc_buffer_free(packet);
1093
1094   return SILC_SKE_STATUS_OK;
1095 }
1096
1097 /* Assembles security properties to Key Exchange Start Payload to be
1098    sent to the remote end. This checks system wide (SILC system, that is)
1099    settings and chooses from those. However, if other properties
1100    should be used this function is easy to replace by another function,
1101    as, this function is called by the caller of the protocol and not
1102    by the protocol itself. */
1103
1104 SilcSKEStatus 
1105 silc_ske_assemble_security_properties(SilcSKE ske,
1106                                       unsigned char flags,
1107                                       char *version,
1108                                       SilcSKEStartPayload **return_payload)
1109 {
1110   SilcSKEStartPayload *rp;
1111   int i;
1112
1113   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1114
1115   rp = silc_calloc(1, sizeof(*rp));
1116
1117   /* Set flags */
1118   rp->flags = flags;
1119
1120   /* Set random cookie */
1121   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1122   for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1123     rp->cookie[i] = silc_rng_get_byte(ske->rng);
1124   rp->cookie_len = SILC_SKE_COOKIE_LEN;
1125
1126   /* Put version */
1127   rp->version = strdup(version);
1128   rp->version_len = strlen(version);
1129
1130   /* Get supported Key Exhange groups */
1131   rp->ke_grp_list = silc_ske_get_supported_groups();
1132   rp->ke_grp_len = strlen(rp->ke_grp_list);
1133
1134   /* Get supported PKCS algorithms */
1135   rp->pkcs_alg_list = silc_pkcs_get_supported();
1136   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1137
1138   /* Get supported encryption algorithms */
1139   rp->enc_alg_list = silc_cipher_get_supported();
1140   rp->enc_alg_len = strlen(rp->enc_alg_list);
1141
1142   /* Get supported hash algorithms */
1143   rp->hash_alg_list = silc_hash_get_supported();
1144   rp->hash_alg_len = strlen(rp->hash_alg_list);
1145
1146   /* Get supported HMACs */
1147   rp->hmac_alg_list = silc_hmac_get_supported();
1148   rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1149
1150   /* XXX */
1151   /* Get supported compression algorithms */
1152   rp->comp_alg_list = strdup("");
1153   rp->comp_alg_len = 0;
1154
1155   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1156     2 + rp->version_len +
1157     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
1158     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
1159     2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1160
1161   *return_payload = rp;
1162
1163   return SILC_SKE_STATUS_OK;
1164 }
1165
1166 /* Selects the supported security properties from the remote end's Key 
1167    Exchange Start Payload. */
1168
1169 SilcSKEStatus 
1170 silc_ske_select_security_properties(SilcSKE ske,
1171                                     char *version,
1172                                     SilcSKEStartPayload *payload,
1173                                     SilcSKEStartPayload *remote_payload)
1174 {
1175   SilcSKEStatus status;
1176   SilcSKEStartPayload *rp;
1177   char *cp;
1178   int len;
1179
1180   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1181
1182   rp = remote_payload;
1183
1184   /* Check version string */
1185   if (ske->callbacks->check_version) {
1186     status = ske->callbacks->check_version(ske, rp->version, 
1187                                            rp->version_len,
1188                                            ske->callbacks->context);
1189     if (status != SILC_SKE_STATUS_OK) {
1190       ske->status = status;
1191       return status;
1192     }
1193   }
1194
1195   /* Flags are returned unchanged. */
1196   payload->flags = rp->flags;
1197
1198   /* Take cookie, we must return it to sender unmodified. */
1199   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1200   payload->cookie_len = SILC_SKE_COOKIE_LEN;
1201   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1202
1203   /* Put our version to our reply */
1204   payload->version = strdup(version);
1205   payload->version_len = strlen(version);
1206
1207   /* Get supported Key Exchange groups */
1208   cp = rp->ke_grp_list;
1209   if (cp && strchr(cp, ',')) {
1210     while(cp) {
1211       char *item;
1212
1213       len = strcspn(cp, ",");
1214       item = silc_calloc(len + 1, sizeof(char));
1215       memcpy(item, cp, len);
1216
1217       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1218
1219       if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1220         SILC_LOG_DEBUG(("Found KE group `%s'", item));
1221
1222         payload->ke_grp_len = len;
1223         payload->ke_grp_list = item;
1224         break;
1225       }
1226
1227       cp += len;
1228       if (strlen(cp) == 0)
1229         cp = NULL;
1230       else
1231         cp++;
1232
1233       if (item)
1234         silc_free(item);
1235     }
1236
1237     if (!payload->ke_grp_len && !payload->ke_grp_list) {
1238       SILC_LOG_DEBUG(("Could not find supported KE group"));
1239       silc_free(payload);
1240       return SILC_SKE_STATUS_UNKNOWN_GROUP;
1241     }
1242   } else {
1243
1244     if (!rp->ke_grp_len) {
1245       SILC_LOG_DEBUG(("KE group not defined in payload"));
1246       silc_free(payload);
1247       return SILC_SKE_STATUS_BAD_PAYLOAD;
1248     }
1249
1250     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1251     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1252
1253     payload->ke_grp_len = rp->ke_grp_len;
1254     payload->ke_grp_list = strdup(rp->ke_grp_list);
1255   }
1256
1257   /* Get supported PKCS algorithms */
1258   cp = rp->pkcs_alg_list;
1259   if (cp && strchr(cp, ',')) {
1260     while(cp) {
1261       char *item;
1262
1263       len = strcspn(cp, ",");
1264       item = silc_calloc(len + 1, sizeof(char));
1265       memcpy(item, cp, len);
1266
1267       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1268
1269       if (silc_pkcs_is_supported(item) == TRUE) {
1270         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1271
1272         payload->pkcs_alg_len = len;
1273         payload->pkcs_alg_list = item;
1274         break;
1275       }
1276
1277       cp += len;
1278       if (strlen(cp) == 0)
1279         cp = NULL;
1280       else
1281         cp++;
1282
1283       if (item)
1284         silc_free(item);
1285     }
1286
1287     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1288       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1289       silc_free(payload->ke_grp_list);
1290       silc_free(payload);
1291       return SILC_SKE_STATUS_UNKNOWN_PKCS;
1292     }
1293   } else {
1294
1295     if (!rp->pkcs_alg_len) {
1296       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1297       silc_free(payload->ke_grp_list);
1298       silc_free(payload);
1299       return SILC_SKE_STATUS_BAD_PAYLOAD;
1300     }
1301
1302     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1303     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1304
1305     payload->pkcs_alg_len = rp->pkcs_alg_len;
1306     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1307   }
1308
1309   /* Get supported encryption algorithms */
1310   cp = rp->enc_alg_list;
1311   if (cp && strchr(cp, ',')) {
1312     while(cp) {
1313       char *item;
1314
1315       len = strcspn(cp, ",");
1316       item = silc_calloc(len + 1, sizeof(char));
1317       memcpy(item, cp, len);
1318
1319       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1320
1321       if (silc_cipher_is_supported(item) == TRUE) {
1322         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1323
1324         payload->enc_alg_len = len;
1325         payload->enc_alg_list = item;
1326         break;
1327       }
1328
1329       cp += len;
1330       if (strlen(cp) == 0)
1331         cp = NULL;
1332       else
1333         cp++;
1334
1335       if (item)
1336         silc_free(item);
1337     }
1338
1339     if (!payload->enc_alg_len && !payload->enc_alg_list) {
1340       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1341       silc_free(payload->ke_grp_list);
1342       silc_free(payload->pkcs_alg_list);
1343       silc_free(payload);
1344       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1345     }
1346   } else {
1347
1348     if (!rp->enc_alg_len) {
1349       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1350       silc_free(payload->ke_grp_list);
1351       silc_free(payload->pkcs_alg_list);
1352       silc_free(payload);
1353       return SILC_SKE_STATUS_BAD_PAYLOAD;
1354     }
1355
1356     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1357                     rp->enc_alg_list));
1358
1359     payload->enc_alg_len = rp->enc_alg_len;
1360     payload->enc_alg_list = strdup(rp->enc_alg_list);
1361   }
1362
1363   /* Get supported hash algorithms */
1364   cp = rp->hash_alg_list;
1365   if (cp && strchr(cp, ',')) {
1366     while(cp) {
1367       char *item;
1368
1369       len = strcspn(cp, ",");
1370       item = silc_calloc(len + 1, sizeof(char));
1371       memcpy(item, cp, len);
1372
1373       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1374
1375       if (silc_hash_is_supported(item) == TRUE) {
1376         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1377
1378         payload->hash_alg_len = len;
1379         payload->hash_alg_list = item;
1380         break;
1381       }
1382
1383       cp += len;
1384       if (strlen(cp) == 0)
1385         cp = NULL;
1386       else
1387         cp++;
1388
1389       if (item)
1390         silc_free(item);
1391     }
1392
1393     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1394       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1395       silc_free(payload->ke_grp_list);
1396       silc_free(payload->pkcs_alg_list);
1397       silc_free(payload->enc_alg_list);
1398       silc_free(payload);
1399       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1400     }
1401   } else {
1402
1403     if (!rp->hash_alg_len) {
1404       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1405       silc_free(payload->ke_grp_list);
1406       silc_free(payload->pkcs_alg_list);
1407       silc_free(payload->enc_alg_list);
1408       silc_free(payload);
1409       return SILC_SKE_STATUS_BAD_PAYLOAD;
1410     }
1411
1412     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1413                     rp->hash_alg_list));
1414
1415     payload->hash_alg_len = rp->hash_alg_len;
1416     payload->hash_alg_list = strdup(rp->hash_alg_list);
1417   }
1418
1419   /* Get supported HMACs */
1420   cp = rp->hmac_alg_list;
1421   if (cp && strchr(cp, ',')) {
1422     while(cp) {
1423       char *item;
1424
1425       len = strcspn(cp, ",");
1426       item = silc_calloc(len + 1, sizeof(char));
1427       memcpy(item, cp, len);
1428
1429       SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1430
1431       if (silc_hmac_is_supported(item) == TRUE) {
1432         SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1433
1434         payload->hmac_alg_len = len;
1435         payload->hmac_alg_list = item;
1436         break;
1437       }
1438
1439       cp += len;
1440       if (strlen(cp) == 0)
1441         cp = NULL;
1442       else
1443         cp++;
1444
1445       if (item)
1446         silc_free(item);
1447     }
1448
1449     if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1450       SILC_LOG_DEBUG(("Could not find supported HMAC"));
1451       silc_free(payload->ke_grp_list);
1452       silc_free(payload->pkcs_alg_list);
1453       silc_free(payload->enc_alg_list);
1454       silc_free(payload->hash_alg_list);
1455       silc_free(payload);
1456       return SILC_SKE_STATUS_UNKNOWN_HMAC;
1457     }
1458   } else {
1459
1460     if (!rp->hmac_alg_len) {
1461       SILC_LOG_DEBUG(("HMAC not defined in payload"));
1462       silc_free(payload->ke_grp_list);
1463       silc_free(payload->pkcs_alg_list);
1464       silc_free(payload->enc_alg_list);
1465       silc_free(payload->hash_alg_list);
1466       silc_free(payload);
1467       return SILC_SKE_STATUS_BAD_PAYLOAD;
1468     }
1469
1470     SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1471                     rp->hmac_alg_list));
1472
1473     payload->hmac_alg_len = rp->hmac_alg_len;
1474     payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1475   }
1476
1477 #if 0
1478   /* Get supported compression algorithms */
1479   cp = rp->hash_alg_list;
1480   if (cp && strchr(cp, ',')) {
1481     while(cp) {
1482       char *item;
1483
1484       len = strcspn(cp, ",");
1485       item = silc_calloc(len + 1, sizeof(char));
1486       memcpy(item, cp, len);
1487
1488       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1489
1490       if (silc_hash_is_supported(item) == TRUE) {
1491         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1492
1493         payload->hash_alg_len = len;
1494         payload->hash_alg_list = item;
1495         break;
1496       }
1497
1498       cp += len;
1499       if (strlen(cp) == 0)
1500         cp = NULL;
1501       else
1502         cp++;
1503
1504       if (item)
1505         silc_free(item);
1506     }
1507
1508     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1509       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1510       silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1511       silc_free(payload->ke_grp_list);
1512       silc_free(payload->pkcs_alg_list);
1513       silc_free(payload->enc_alg_list);
1514       silc_free(payload);
1515       return;
1516     }
1517   } else {
1518
1519   }
1520 #endif
1521
1522   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1523     2 + payload->version_len + 
1524     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1525     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1526     2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1527
1528   return SILC_SKE_STATUS_OK;
1529 }
1530
1531 /* Creates random number such that 1 < rnd < n and at most length
1532    of len bits. The rnd sent as argument must be initialized. */
1533
1534 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, 
1535                                   uint32 len, 
1536                                   SilcMPInt *rnd)
1537 {
1538   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1539   unsigned char *string;
1540
1541   SILC_LOG_DEBUG(("Creating random number"));
1542
1543   /* Get the random number as string */
1544   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1545   if (!string)
1546     return SILC_SKE_STATUS_ERROR;
1547
1548   /* Decode the string into a MP integer */
1549   silc_mp_bin2mp(string, (len / 8), rnd);
1550   silc_mp_mod_2exp(rnd, rnd, len);
1551
1552   /* Checks */
1553   if (silc_mp_cmp_ui(rnd, 1) < 0)
1554     status = SILC_SKE_STATUS_ERROR;
1555
1556   if (silc_mp_cmp(rnd, n) >= 0)
1557     status = SILC_SKE_STATUS_ERROR;
1558
1559   memset(string, 'F', (len / 8));
1560   silc_free(string);
1561
1562   return status;
1563 }
1564
1565 /* Creates a hash value HASH as defined in the SKE protocol. If the
1566    `initiator' is TRUE then this function is used to create the HASH_i
1567    hash value defined in the protocol. If it is FALSE then this is used
1568    to create the HASH value defined by the protocol. */
1569
1570 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1571                                  unsigned char *return_hash,
1572                                  uint32 *return_hash_len,
1573                                  int initiator)
1574 {
1575   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1576   SilcBuffer buf;
1577   unsigned char *e, *f, *KEY;
1578   uint32 e_len, f_len, KEY_len;
1579   int ret;
1580
1581   SILC_LOG_DEBUG(("Start"));
1582
1583   if (initiator == FALSE) {
1584     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1585     f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1586     KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1587     
1588     /* Format the buffer used to compute the hash value */
1589     /* XXX Backward support for 0.6.1 */
1590     if (ske->backward_version == 1) {
1591       SILC_LOG_DEBUG(("*********** Using old KE payload"));
1592       buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1593                               ske->ke2_payload->pk_len + e_len + 
1594                               f_len + KEY_len);
1595       silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1596
1597       ret = 
1598         silc_buffer_format(buf,
1599                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1600                                                 ske->start_payload_copy->len),
1601                            SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1602                                                 ske->ke2_payload->pk_len),
1603                            SILC_STR_UI_XNSTRING(e, e_len),
1604                            SILC_STR_UI_XNSTRING(f, f_len),
1605                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
1606                            SILC_STR_END);
1607     } else {
1608       /* Initiator is not required to send its public key */
1609       SILC_LOG_DEBUG(("*********** Using new KE payload"));
1610       buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1611                               ske->ke2_payload->pk_len + 
1612                               ske->ke1_payload->pk_len + 
1613                               e_len + f_len + KEY_len);
1614       silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1615
1616       if (!ske->ke1_payload->pk_data) {
1617         ret = 
1618           silc_buffer_format(buf,
1619                              SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1620                                                   data,
1621                                                   ske->start_payload_copy->
1622                                                   len),
1623                              SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1624                                                   ske->ke2_payload->pk_len),
1625                              SILC_STR_UI_XNSTRING(e, e_len),
1626                              SILC_STR_UI_XNSTRING(f, f_len),
1627                              SILC_STR_UI_XNSTRING(KEY, KEY_len),
1628                              SILC_STR_END);
1629       } else {
1630         ret = 
1631           silc_buffer_format(buf,
1632                              SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1633                                                   data,
1634                                                   ske->start_payload_copy->
1635                                                   len),
1636                              SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1637                                                   ske->ke2_payload->pk_len),
1638                              SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
1639                                                   ske->ke1_payload->pk_len),
1640                              SILC_STR_UI_XNSTRING(e, e_len),
1641                              SILC_STR_UI_XNSTRING(f, f_len),
1642                              SILC_STR_UI_XNSTRING(KEY, KEY_len),
1643                              SILC_STR_END);
1644       }
1645     }
1646     if (ret == -1) {
1647       silc_buffer_free(buf);
1648       memset(e, 0, e_len);
1649       memset(f, 0, f_len);
1650       memset(KEY, 0, KEY_len);
1651       silc_free(e);
1652       silc_free(f);
1653       silc_free(KEY);
1654       return SILC_SKE_STATUS_ERROR;
1655     }
1656
1657     memset(e, 0, e_len);
1658     memset(f, 0, f_len);
1659     memset(KEY, 0, KEY_len);
1660     silc_free(e);
1661     silc_free(f);
1662     silc_free(KEY);
1663   } else {
1664     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1665
1666     buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1667                             ske->ke1_payload->pk_len + e_len);
1668     silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1669     
1670     /* Format the buffer used to compute the hash value */
1671     ret = 
1672       silc_buffer_format(buf,
1673                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1674                                               ske->start_payload_copy->len),
1675                          SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
1676                                               ske->ke1_payload->pk_len),
1677                          SILC_STR_UI_XNSTRING(e, e_len),
1678                          SILC_STR_END);
1679     if (ret == -1) {
1680       silc_buffer_free(buf);
1681       memset(e, 0, e_len);
1682       silc_free(e);
1683       return SILC_SKE_STATUS_ERROR;
1684     }
1685
1686     memset(e, 0, e_len);
1687     silc_free(e);
1688   }
1689
1690   /* Make the hash */
1691   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1692   *return_hash_len = ske->prop->hash->hash->hash_len;
1693
1694   if (initiator == FALSE) {
1695     SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1696   } else {
1697     SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1698   }
1699
1700   silc_buffer_free(buf);
1701
1702   return status;
1703 }
1704
1705 /* Processes the provided key material `data' as the SILC protocol 
1706    specification defines. */
1707
1708 SilcSKEStatus 
1709 silc_ske_process_key_material_data(unsigned char *data,
1710                                    uint32 data_len,
1711                                    uint32 req_iv_len,
1712                                    uint32 req_enc_key_len,
1713                                    uint32 req_hmac_key_len,
1714                                    SilcHash hash,
1715                                    SilcSKEKeyMaterial *key)
1716 {
1717   SilcBuffer buf;
1718   unsigned char hashd[32];
1719   uint32 hash_len = req_hmac_key_len;
1720   uint32 enc_key_len = req_enc_key_len / 8;
1721
1722   SILC_LOG_DEBUG(("Start"));
1723
1724   if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1725     return SILC_SKE_STATUS_ERROR;
1726
1727   buf = silc_buffer_alloc(1 + data_len);
1728   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1729   silc_buffer_format(buf,
1730                      SILC_STR_UI_CHAR(0),
1731                      SILC_STR_UI_XNSTRING(data, data_len),
1732                      SILC_STR_END);
1733
1734   /* Take IVs */
1735   memset(hashd, 0, sizeof(hashd));
1736   buf->data[0] = 0;
1737   silc_hash_make(hash, buf->data, buf->len, hashd);
1738   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1739   memcpy(key->send_iv, hashd, req_iv_len);
1740   memset(hashd, 0, sizeof(hashd));
1741   buf->data[0] = 1;
1742   silc_hash_make(hash, buf->data, buf->len, hashd);
1743   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1744   memcpy(key->receive_iv, hashd, req_iv_len);
1745   key->iv_len = req_iv_len;
1746
1747   /* Take the encryption keys. If requested key size is more than
1748      the size of hash length we will distribute more key material
1749      as protocol defines. */
1750   buf->data[0] = 2;
1751   if (enc_key_len > hash_len) {
1752     SilcBuffer dist;
1753     unsigned char k1[32], k2[32], k3[32];
1754     unsigned char *dtmp;
1755     
1756     /* XXX */
1757     if (enc_key_len > (3 * hash_len))
1758       return SILC_SKE_STATUS_ERROR;
1759     
1760     /* Take first round */
1761     memset(k1, 0, sizeof(k1));
1762     silc_hash_make(hash, buf->data, buf->len, k1);
1763     
1764     /* Take second round */
1765     dist = silc_buffer_alloc(data_len + hash_len);
1766     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1767     silc_buffer_format(dist,
1768                        SILC_STR_UI_XNSTRING(data, data_len),
1769                        SILC_STR_UI_XNSTRING(k1, hash_len),
1770                        SILC_STR_END);
1771     memset(k2, 0, sizeof(k2));
1772     silc_hash_make(hash, dist->data, dist->len, k2);
1773
1774     /* Take third round */
1775     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1776     silc_buffer_pull_tail(dist, hash_len);
1777     silc_buffer_pull(dist, data_len + hash_len);
1778     silc_buffer_format(dist,
1779                        SILC_STR_UI_XNSTRING(k2, hash_len),
1780                        SILC_STR_END);
1781     silc_buffer_push(dist, data_len + hash_len);
1782     memset(k3, 0, sizeof(k3));
1783     silc_hash_make(hash, dist->data, dist->len, k3);
1784
1785     /* Then, save the keys */
1786     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1787     memcpy(dtmp, k1, hash_len);
1788     memcpy(dtmp + hash_len, k2, hash_len);
1789     memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1790
1791     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1792     memcpy(key->send_enc_key, dtmp, enc_key_len);
1793     key->enc_key_len = req_enc_key_len;
1794
1795     memset(dtmp, 0, (3 * hash_len));
1796     memset(k1, 0, sizeof(k1));
1797     memset(k2, 0, sizeof(k2));
1798     memset(k3, 0, sizeof(k3));
1799     silc_free(dtmp);
1800     silc_buffer_free(dist);
1801   } else {
1802     /* Take normal hash as key */
1803     memset(hashd, 0, sizeof(hashd));
1804     silc_hash_make(hash, buf->data, buf->len, hashd);
1805     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1806     memcpy(key->send_enc_key, hashd, enc_key_len);
1807     key->enc_key_len = req_enc_key_len;
1808   }
1809
1810   buf->data[0] = 3;
1811   if (enc_key_len > hash_len) {
1812     SilcBuffer dist;
1813     unsigned char k1[32], k2[32], k3[32];
1814     unsigned char *dtmp;
1815     
1816     /* XXX */
1817     if (enc_key_len > (3 * hash_len))
1818       return SILC_SKE_STATUS_ERROR;
1819     
1820     /* Take first round */
1821     memset(k1, 0, sizeof(k1));
1822     silc_hash_make(hash, buf->data, buf->len, k1);
1823     
1824     /* Take second round */
1825     dist = silc_buffer_alloc(data_len + hash_len);
1826     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1827     silc_buffer_format(dist,
1828                        SILC_STR_UI_XNSTRING(data, data_len),
1829                        SILC_STR_UI_XNSTRING(k1, hash_len),
1830                        SILC_STR_END);
1831     memset(k2, 0, sizeof(k2));
1832     silc_hash_make(hash, dist->data, dist->len, k2);
1833     
1834     /* Take third round */
1835     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1836     silc_buffer_pull_tail(dist, hash_len);
1837     silc_buffer_pull(dist, data_len + hash_len);
1838     silc_buffer_format(dist,
1839                        SILC_STR_UI_XNSTRING(k2, hash_len),
1840                        SILC_STR_END);
1841     silc_buffer_push(dist, data_len + hash_len);
1842     memset(k3, 0, sizeof(k3));
1843     silc_hash_make(hash, dist->data, dist->len, k3);
1844
1845     /* Then, save the keys */
1846     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1847     memcpy(dtmp, k1, hash_len);
1848     memcpy(dtmp + hash_len, k2, hash_len);
1849     memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1850
1851     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1852     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1853     key->enc_key_len = req_enc_key_len;
1854
1855     memset(dtmp, 0, (3 * hash_len));
1856     memset(k1, 0, sizeof(k1));
1857     memset(k2, 0, sizeof(k2));
1858     memset(k3, 0, sizeof(k3));
1859     silc_free(dtmp);
1860     silc_buffer_free(dist);
1861   } else {
1862     /* Take normal hash as key */
1863     memset(hashd, 0, sizeof(hashd));
1864     silc_hash_make(hash, buf->data, buf->len, hashd);
1865     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1866     memcpy(key->receive_enc_key, hashd, enc_key_len);
1867     key->enc_key_len = req_enc_key_len;
1868   }
1869
1870   /* Take HMAC keys */
1871   memset(hashd, 0, sizeof(hashd));
1872   buf->data[0] = 4;
1873   silc_hash_make(hash, buf->data, buf->len, hashd);
1874   key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1875   memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
1876   memset(hashd, 0, sizeof(hashd));
1877   buf->data[0] = 5;
1878   silc_hash_make(hash, buf->data, buf->len, hashd);
1879   key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1880   memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
1881   key->hmac_key_len = req_hmac_key_len;
1882   memset(hashd, 0, sizeof(hashd));
1883
1884   silc_buffer_free(buf);
1885
1886   return SILC_SKE_STATUS_OK;
1887 }
1888
1889 /* Processes negotiated key material as protocol specifies. This returns
1890    the actual keys to be used in the SILC. */
1891
1892 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1893                                             uint32 req_iv_len,
1894                                             uint32 req_enc_key_len,
1895                                             uint32 req_hmac_key_len,
1896                                             SilcSKEKeyMaterial *key)
1897 {
1898   SilcSKEStatus status;
1899   SilcBuffer buf;
1900   unsigned char *tmpbuf;
1901   uint32 klen;
1902
1903   /* Encode KEY to binary data */
1904   tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1905
1906   buf = silc_buffer_alloc(klen + ske->hash_len);
1907   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1908   silc_buffer_format(buf,
1909                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
1910                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1911                      SILC_STR_END);
1912
1913   /* Process the key material */
1914   status = silc_ske_process_key_material_data(buf->data, buf->len,
1915                                               req_iv_len, req_enc_key_len,
1916                                               req_hmac_key_len, 
1917                                               ske->prop->hash, key);
1918
1919   memset(tmpbuf, 0, klen);
1920   silc_free(tmpbuf);
1921   silc_buffer_free(buf);
1922
1923   return status;
1924 }
1925
1926 /* Free key material structure */
1927
1928 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1929 {
1930   if (!key)
1931     return;
1932
1933   if (key->send_iv)
1934     silc_free(key->send_iv);
1935   if (key->receive_iv)
1936     silc_free(key->receive_iv);
1937   if (key->send_enc_key) {
1938     memset(key->send_enc_key, 0, key->enc_key_len / 8);
1939     silc_free(key->send_enc_key);
1940   }
1941   if (key->receive_enc_key) {
1942     memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1943     silc_free(key->receive_enc_key);
1944   }
1945   if (key->send_hmac_key) {
1946     memset(key->send_hmac_key, 0, key->hmac_key_len);
1947     silc_free(key->send_hmac_key);
1948   }
1949   if (key->receive_hmac_key) {
1950     memset(key->receive_hmac_key, 0, key->hmac_key_len);
1951     silc_free(key->receive_hmac_key);
1952   }
1953   silc_free(key);
1954 }
1955
1956 const char *silc_ske_status_string[] = 
1957 {
1958   /* Official */
1959   "Ok",
1960   "Unkown error occurred",
1961   "Bad payload in packet",
1962   "Unsupported group",
1963   "Unsupported cipher",
1964   "Unsupported PKCS",
1965   "Unsupported hash function",
1966   "Unsupported HMAC",
1967   "Unsupported public key (or certificate)",
1968   "Incorrect signature",
1969   "Bad or unsupported version",
1970   "Invalid cookie",
1971
1972   /* Other errors */
1973   "Pending",
1974   "Remote did not provide public key",
1975   "Key exchange protocol is not active",
1976   "Bad reserved field in packet",
1977   "Bad payload length in packet",
1978   "Incorrect hash",
1979
1980   NULL
1981 };
1982
1983 /* Maps status to readable string and returns the string. If string is not
1984    found and empty character string ("") is returned. */
1985
1986 const char *silc_ske_map_status(SilcSKEStatus status)
1987 {
1988   int i;
1989
1990   for (i = 0; silc_ske_status_string[i]; i++)
1991     if (status == i)
1992       return silc_ske_status_string[i];
1993
1994   return "";
1995 }