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