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