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