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