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