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