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