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