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