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