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