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