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 "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     return status;
220   }
221
222   /* Check that the cookie is returned unmodified */
223   if (memcmp(ske->start_payload->cookie, payload->cookie,
224              ske->start_payload->cookie_len)) {
225     SILC_LOG_DEBUG(("Responder modified our cookie and it must not do it"));
226     ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
227     silc_ske_payload_start_free(ske->start_payload);
228     return status;
229   }
230
231   /* Free our KE Start Payload context, we don't need it anymore. */
232   silc_ske_payload_start_free(ske->start_payload);
233
234   /* Take the selected security properties into use while doing
235      the key exchange. This is used only while doing the key 
236      exchange. The same data is returned to upper levels by calling
237      the callback function. */
238   ske->prop = prop = silc_calloc(1, sizeof(*prop));
239   prop->flags = payload->flags;
240   status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
241   if (status != SILC_SKE_STATUS_OK)
242     goto err;
243
244   prop->group = group;
245
246   if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
247     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
248     goto err;
249   }
250
251   if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
252     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
253     goto err;
254   }
255
256   if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
257     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
258     goto err;
259   }
260
261   if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
262     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
263     goto err;
264   }
265
266   /* Save remote's KE Start Payload */
267   ske->start_payload = payload;
268
269   /* Return the received payload by calling the callback function. */
270   if (ske->callbacks->payload_receive)
271     (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
272
273   return status;
274
275  err:
276   if (payload)
277     silc_ske_payload_start_free(payload);
278
279   silc_free(group);
280
281   if (prop->pkcs)
282     silc_pkcs_free(prop->pkcs);
283   if (prop->cipher)
284     silc_cipher_free(prop->cipher);
285   if (prop->hash)
286     silc_hash_free(prop->hash);
287   if (prop->hmac)
288     silc_hmac_free(prop->hmac);
289   silc_free(prop);
290   ske->prop = NULL;
291
292   if (status == SILC_SKE_STATUS_OK)
293     return SILC_SKE_STATUS_ERROR;
294
295   ske->status = status;
296   return status;
297 }
298
299 /* This function creates random number x, such that 1 < x < q and 
300    computes e = g ^ x mod p and sends the result to the remote end in 
301    Key Exchange Payload. */
302
303 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
304                                          SilcPublicKey public_key,
305                                          SilcPrivateKey private_key)
306 {
307   SilcSKEStatus status = SILC_SKE_STATUS_OK;
308   SilcBuffer payload_buf;
309   SilcMPInt *x;
310   SilcSKEKEPayload *payload;
311   uint32 pk_len;
312
313   SILC_LOG_DEBUG(("Start"));
314
315   /* Create the random number x, 1 < x < q. */
316   x = silc_calloc(1, sizeof(*x));
317   silc_mp_init(x);
318   status = 
319     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
320                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
321                         x);
322   if (status != SILC_SKE_STATUS_OK) {
323     silc_mp_uninit(x);
324     silc_free(x);
325     ske->status = status;
326     return status;
327   }
328
329   /* Encode the result to Key Exchange Payload. */
330
331   payload = silc_calloc(1, sizeof(*payload));
332   ske->ke1_payload = payload;
333
334   SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
335
336   /* Do the Diffie Hellman computation, e = g ^ x mod p */
337   silc_mp_init(&payload->x);
338   silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x, 
339                   &ske->prop->group->group);
340
341   /* Get public key */
342   if (public_key) {
343     payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
344     if (!payload->pk_data) {
345       silc_mp_uninit(x);
346       silc_free(x);
347       silc_mp_uninit(&payload->x);
348       silc_free(payload);
349       ske->status = SILC_SKE_STATUS_OK;
350       return ske->status;
351     }
352     payload->pk_len = pk_len;
353   }
354   payload->pk_type = SILC_SKE_PK_TYPE_SILC;
355
356   /* Compute signature data if we are doing mutual authentication */
357   if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
358     unsigned char hash[32], sign[1024];
359     uint32 hash_len, sign_len;
360
361     SILC_LOG_DEBUG(("We are doing mutual authentication"));
362     SILC_LOG_DEBUG(("Computing HASH_i value"));
363
364     /* Compute the hash value */
365     memset(hash, 0, sizeof(hash));
366     silc_ske_make_hash(ske, hash, &hash_len, TRUE);
367
368     SILC_LOG_DEBUG(("Signing HASH_i value"));
369     
370     /* Sign the hash value */
371     silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
372                                    private_key->prv_len);
373     silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
374     payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
375     memcpy(payload->sign_data, sign, sign_len);
376     memset(sign, 0, sizeof(sign));
377     payload->sign_len = sign_len;
378   }
379
380   status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
381   if (status != SILC_SKE_STATUS_OK) {
382     silc_mp_uninit(x);
383     silc_free(x);
384     silc_mp_uninit(&payload->x);
385     silc_free(payload->pk_data);
386     silc_free(payload);
387     ske->status = status;
388     return status;
389   }
390
391   ske->x = x;
392
393   /* Send the packet. */
394   if (ske->callbacks->send_packet)
395     (*ske->callbacks->send_packet)(ske, payload_buf, 
396                                    SILC_PACKET_KEY_EXCHANGE_1, 
397                                    ske->callbacks->context);
398
399   silc_buffer_free(payload_buf);
400
401   return status;
402 }
403
404 /* An initiator finish final callback that is called to indicate that
405    the SKE protocol may continue. */
406
407 static void silc_ske_initiator_finish_final(SilcSKE ske,
408                                             SilcSKEStatus status,
409                                             void *context)
410 {
411   SilcSKEKEPayload *payload;
412   unsigned char hash[32];
413   uint32 hash_len;
414   SilcPublicKey public_key = NULL;
415
416   /* If the SKE was freed during the async call then free it really now,
417      otherwise just decrement the reference counter. */
418   if (ske->status == SILC_SKE_STATUS_FREED) {
419     silc_ske_free(ske);
420     return;
421   } else {
422     ske->users--;
423   }
424
425   payload = ske->ke2_payload;
426
427   /* If the caller returns PENDING status SKE library will assume that
428      the caller will re-call this callback when it is not anymore in
429      PENDING status. */
430   if (status == SILC_SKE_STATUS_PENDING)
431     return;
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   silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
584
585   return SILC_SKE_STATUS_OK;
586
587  err:
588   silc_ske_payload_ke_free(payload);
589   ske->ke2_payload = NULL;
590
591   silc_mp_uninit(ske->KEY);
592   silc_free(ske->KEY);
593   ske->KEY = NULL;
594
595   if (status == SILC_SKE_STATUS_OK)
596     return SILC_SKE_STATUS_ERROR;
597
598   ske->status = status;
599   return status;
600 }
601
602 /* Starts Key Exchange protocol for responder. Responder receives
603    Key Exchange Start Payload from initiator consisting of all the
604    security properties the initiator supports. This function decodes
605    the payload and parses the payload further and selects the right 
606    security properties. */
607
608 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
609                                        SilcSocketConnection sock,
610                                        char *version,
611                                        SilcBuffer start_payload,
612                                        bool mutual_auth)
613 {
614   SilcSKEStatus status = SILC_SKE_STATUS_OK;
615   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
616
617   SILC_LOG_DEBUG(("Start"));
618
619   ske->sock = sock;
620   ske->rng = rng;
621
622   /* Decode the payload */
623   status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
624   if (status != SILC_SKE_STATUS_OK) {
625     ske->status = status;
626     return status;
627   }
628
629   /* Take a copy of the payload buffer for future use. It is used to
630      compute the HASH value. */
631   ske->start_payload_copy = silc_buffer_copy(start_payload);
632
633   /* Force the mutual authentication flag if we want to do it. */
634   if (mutual_auth) {
635     SILC_LOG_DEBUG(("Force mutual authentication"));
636     remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
637   }
638
639   /* Parse and select the security properties from the payload */
640   payload = silc_calloc(1, sizeof(*payload));
641   status = silc_ske_select_security_properties(ske, version,
642                                                payload, remote_payload);
643   if (status != SILC_SKE_STATUS_OK)
644     goto err;
645
646   ske->start_payload = payload;
647
648   /* Call the callback function. */
649   if (ske->callbacks->payload_receive)
650     (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
651
652   return status;
653
654  err:
655   if (remote_payload)
656     silc_ske_payload_start_free(remote_payload);
657   if (payload)
658     silc_free(payload);
659
660   if (status == SILC_SKE_STATUS_OK)
661     return SILC_SKE_STATUS_ERROR;
662
663   ske->status = status;
664   return status;
665 }
666
667 /* The selected security properties from the initiator payload is now 
668    encoded into Key Exchange Start Payload and sent to the initiator. */
669
670 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
671                                          SilcSKEStartPayload *start_payload)
672 {
673   SilcSKEStatus status = SILC_SKE_STATUS_OK;
674   SilcBuffer payload_buf;
675   SilcSKESecurityProperties prop;
676   SilcSKEDiffieHellmanGroup group = NULL;
677
678   SILC_LOG_DEBUG(("Start"));
679
680   /* Allocate security properties from the payload. These are allocated
681      only for this negotiation and will be free'd after KE is over. */
682   ske->prop = prop = silc_calloc(1, sizeof(*prop));
683   prop->flags = start_payload->flags;
684   status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
685   if (status != SILC_SKE_STATUS_OK)
686     goto err;
687
688   prop->group = group;
689
690   if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
691                       &prop->pkcs) == FALSE) {
692     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
693     goto err;
694   }
695
696   if (silc_cipher_alloc(start_payload->enc_alg_list, 
697                         &prop->cipher) == FALSE) {
698     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
699     goto err;
700   }
701
702   if (silc_hash_alloc(start_payload->hash_alg_list,
703                       &prop->hash) == FALSE) {
704     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
705     goto err;
706   }
707
708   if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
709                       &prop->hmac) == FALSE) {
710     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
711     goto err;
712   }
713
714   /* Encode the payload */
715   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
716   if (status != SILC_SKE_STATUS_OK)
717     goto err;
718
719   /* Send the packet. */
720   if (ske->callbacks->send_packet)
721     (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
722                                   ske->callbacks->context);
723
724   silc_buffer_free(payload_buf);
725
726   return status;
727
728  err:
729   if (group)
730     silc_free(group);
731
732   if (prop->pkcs)
733     silc_pkcs_free(prop->pkcs);
734   if (prop->cipher)
735     silc_cipher_free(prop->cipher);
736   if (prop->hash)
737     silc_hash_free(prop->hash);
738   if (prop->hmac)
739     silc_hmac_free(prop->hmac);
740   silc_free(prop);
741   ske->prop = NULL;
742
743   if (status == SILC_SKE_STATUS_OK)
744     return SILC_SKE_STATUS_ERROR;
745
746   ske->status = status;
747   return status;
748 }
749
750 /* An responder phase 2 final callback that is called to indicate that
751    the SKE protocol may continue. */
752
753 static void silc_ske_responder_phase2_final(SilcSKE ske,
754                                             SilcSKEStatus status,
755                                             void *context)
756 {
757   SilcSKEKEPayload *recv_payload, *send_payload;
758   SilcMPInt *x;
759
760   /* If the SKE was freed during the async call then free it really now,
761      otherwise just decrement the reference counter. */
762   if (ske->status == SILC_SKE_STATUS_FREED) {
763     silc_ske_free(ske);
764     return;
765   } else {
766     ske->users--;
767   }
768
769   recv_payload = ske->ke1_payload;
770
771   /* If the caller returns PENDING status SKE library will assume that
772      the caller will re-call this callback when it is not anymore in
773      PENDING status. */
774   if (status == SILC_SKE_STATUS_PENDING)
775     return;
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   silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
938
939   return SILC_SKE_STATUS_OK;
940 }
941
942 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
943    value to be signed and sent to the other end. This then encodes Key
944    Exchange Payload and sends it to the other end. */
945
946 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
947                                         SilcPublicKey public_key,
948                                         SilcPrivateKey private_key,
949                                         SilcSKEPKType pk_type)
950 {
951   SilcSKEStatus status = SILC_SKE_STATUS_OK;
952   SilcBuffer payload_buf;
953   SilcMPInt *KEY;
954   unsigned char hash[32], sign[1024], *pk;
955   uint32 hash_len, sign_len, pk_len;
956
957   SILC_LOG_DEBUG(("Start"));
958
959   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
960
961   /* Compute the shared secret key */
962   KEY = silc_calloc(1, sizeof(*KEY));
963   silc_mp_init(KEY);
964   silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x, 
965                   &ske->prop->group->group);
966   ske->KEY = KEY;
967
968   if (public_key && private_key) {
969     SILC_LOG_DEBUG(("Getting public key"));
970     
971     /* Get the public key */
972     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
973     if (!pk) {
974       status = SILC_SKE_STATUS_ERROR;
975       goto err;
976     }
977     ske->ke2_payload->pk_data = pk;
978     ske->ke2_payload->pk_len = pk_len;
979     
980     SILC_LOG_DEBUG(("Computing HASH value"));
981     
982     /* Compute the hash value */
983     memset(hash, 0, sizeof(hash));
984     status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
985     if (status != SILC_SKE_STATUS_OK)
986       goto err;
987
988     ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
989     memcpy(ske->hash, hash, hash_len);
990     ske->hash_len = hash_len;
991     
992     SILC_LOG_DEBUG(("Signing HASH value"));
993     
994     /* Sign the hash value */
995     silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
996                                    private_key->prv_len);
997     silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
998     ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
999     memcpy(ske->ke2_payload->sign_data, sign, sign_len);
1000     memset(sign, 0, sizeof(sign));
1001     ske->ke2_payload->sign_len = sign_len;
1002   }
1003   ske->ke2_payload->pk_type = pk_type;
1004
1005   /* Encode the Key Exchange Payload */
1006   status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1007                                       &payload_buf);
1008   if (status != SILC_SKE_STATUS_OK)
1009     goto err;
1010
1011   /* Send the packet. */
1012   if (ske->callbacks->send_packet)
1013     (*ske->callbacks->send_packet)(ske, payload_buf, 
1014                                    SILC_PACKET_KEY_EXCHANGE_2,
1015                                    ske->callbacks->context);
1016
1017   silc_buffer_free(payload_buf);
1018
1019   return status;
1020
1021  err:
1022   silc_mp_uninit(ske->KEY);
1023   silc_free(ske->KEY);
1024   ske->KEY = NULL;
1025   silc_ske_payload_ke_free(ske->ke2_payload);
1026
1027   if (status == SILC_SKE_STATUS_OK)
1028     return SILC_SKE_STATUS_ERROR;
1029
1030   ske->status = status;
1031   return status;
1032 }
1033
1034 /* The Key Exchange protocol is ended by calling this function. This
1035    must not be called until the keys are processed like the protocol
1036    defines. This function is for both initiator and responder. */
1037
1038 SilcSKEStatus silc_ske_end(SilcSKE ske)
1039 {
1040   SilcBuffer packet;
1041
1042   SILC_LOG_DEBUG(("Start"));
1043
1044   packet = silc_buffer_alloc(4);
1045   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1046   silc_buffer_format(packet,
1047                      SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1048                      SILC_STR_END);
1049
1050   if (ske->callbacks->send_packet)
1051     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS, 
1052                                    ske->callbacks->context);
1053
1054   silc_buffer_free(packet);
1055
1056   return SILC_SKE_STATUS_OK;
1057 }
1058
1059 /* Aborts the Key Exchange protocol. This is called if error occurs
1060    while performing the protocol. The status argument is the error
1061    status and it is sent to the remote end. */
1062
1063 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1064 {
1065   SilcBuffer packet;
1066
1067   SILC_LOG_DEBUG(("Start"));
1068
1069   packet = silc_buffer_alloc(4);
1070   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1071   silc_buffer_format(packet,
1072                      SILC_STR_UI_INT((uint32)status),
1073                      SILC_STR_END);
1074
1075   if (ske->callbacks->send_packet)
1076     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE, 
1077                                    ske->callbacks->context);
1078
1079   silc_buffer_free(packet);
1080
1081   return SILC_SKE_STATUS_OK;
1082 }
1083
1084 /* Assembles security properties to Key Exchange Start Payload to be
1085    sent to the remote end. This checks system wide (SILC system, that is)
1086    settings and chooses from those. However, if other properties
1087    should be used this function is easy to replace by another function,
1088    as, this function is called by the caller of the protocol and not
1089    by the protocol itself. */
1090
1091 SilcSKEStatus 
1092 silc_ske_assemble_security_properties(SilcSKE ske,
1093                                       unsigned char flags,
1094                                       char *version,
1095                                       SilcSKEStartPayload **return_payload)
1096 {
1097   SilcSKEStartPayload *rp;
1098   int i;
1099
1100   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1101
1102   rp = silc_calloc(1, sizeof(*rp));
1103
1104   /* Set flags */
1105   rp->flags = flags;
1106
1107   /* Set random cookie */
1108   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1109   for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1110     rp->cookie[i] = silc_rng_get_byte(ske->rng);
1111   rp->cookie_len = SILC_SKE_COOKIE_LEN;
1112
1113   /* Put version */
1114   rp->version = strdup(version);
1115   rp->version_len = strlen(version);
1116
1117   /* Get supported Key Exhange groups */
1118   rp->ke_grp_list = silc_ske_get_supported_groups();
1119   rp->ke_grp_len = strlen(rp->ke_grp_list);
1120
1121   /* Get supported PKCS algorithms */
1122   rp->pkcs_alg_list = silc_pkcs_get_supported();
1123   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1124
1125   /* Get supported encryption algorithms */
1126   rp->enc_alg_list = silc_cipher_get_supported();
1127   rp->enc_alg_len = strlen(rp->enc_alg_list);
1128
1129   /* Get supported hash algorithms */
1130   rp->hash_alg_list = silc_hash_get_supported();
1131   rp->hash_alg_len = strlen(rp->hash_alg_list);
1132
1133   /* Get supported HMACs */
1134   rp->hmac_alg_list = silc_hmac_get_supported();
1135   rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1136
1137   /* XXX */
1138   /* Get supported compression algorithms */
1139   rp->comp_alg_list = strdup("");
1140   rp->comp_alg_len = 0;
1141
1142   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1143     2 + rp->version_len +
1144     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
1145     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
1146     2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1147
1148   *return_payload = rp;
1149
1150   return SILC_SKE_STATUS_OK;
1151 }
1152
1153 /* Selects the supported security properties from the remote end's Key 
1154    Exchange Start Payload. */
1155
1156 SilcSKEStatus 
1157 silc_ske_select_security_properties(SilcSKE ske,
1158                                     char *version,
1159                                     SilcSKEStartPayload *payload,
1160                                     SilcSKEStartPayload *remote_payload)
1161 {
1162   SilcSKEStatus status;
1163   SilcSKEStartPayload *rp;
1164   char *cp;
1165   int len;
1166
1167   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1168
1169   rp = remote_payload;
1170
1171   /* Check version string */
1172   if (ske->callbacks->check_version) {
1173     status = ske->callbacks->check_version(ske, rp->version, 
1174                                            rp->version_len,
1175                                            ske->callbacks->context);
1176     if (status != SILC_SKE_STATUS_OK) {
1177       ske->status = status;
1178       return status;
1179     }
1180   }
1181
1182   /* Flags are returned unchanged. */
1183   payload->flags = rp->flags;
1184
1185   /* Take cookie, we must return it to sender unmodified. */
1186   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1187   payload->cookie_len = SILC_SKE_COOKIE_LEN;
1188   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1189
1190   /* Put our version to our reply */
1191   payload->version = strdup(version);
1192   payload->version_len = strlen(version);
1193
1194   /* Get supported Key Exchange groups */
1195   cp = rp->ke_grp_list;
1196   if (cp && strchr(cp, ',')) {
1197     while(cp) {
1198       char *item;
1199
1200       len = strcspn(cp, ",");
1201       item = silc_calloc(len + 1, sizeof(char));
1202       memcpy(item, cp, len);
1203
1204       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1205
1206       if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1207         SILC_LOG_DEBUG(("Found KE group `%s'", item));
1208
1209         payload->ke_grp_len = len;
1210         payload->ke_grp_list = item;
1211         break;
1212       }
1213
1214       cp += len;
1215       if (strlen(cp) == 0)
1216         cp = NULL;
1217       else
1218         cp++;
1219
1220       if (item)
1221         silc_free(item);
1222     }
1223
1224     if (!payload->ke_grp_len && !payload->ke_grp_list) {
1225       SILC_LOG_DEBUG(("Could not find supported KE group"));
1226       silc_free(payload);
1227       return SILC_SKE_STATUS_UNKNOWN_GROUP;
1228     }
1229   } else {
1230
1231     if (!rp->ke_grp_len) {
1232       SILC_LOG_DEBUG(("KE group not defined in payload"));
1233       silc_free(payload);
1234       return SILC_SKE_STATUS_BAD_PAYLOAD;
1235     }
1236
1237     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1238     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1239
1240     payload->ke_grp_len = rp->ke_grp_len;
1241     payload->ke_grp_list = strdup(rp->ke_grp_list);
1242   }
1243
1244   /* Get supported PKCS algorithms */
1245   cp = rp->pkcs_alg_list;
1246   if (cp && strchr(cp, ',')) {
1247     while(cp) {
1248       char *item;
1249
1250       len = strcspn(cp, ",");
1251       item = silc_calloc(len + 1, sizeof(char));
1252       memcpy(item, cp, len);
1253
1254       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1255
1256       if (silc_pkcs_is_supported(item) == TRUE) {
1257         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1258
1259         payload->pkcs_alg_len = len;
1260         payload->pkcs_alg_list = item;
1261         break;
1262       }
1263
1264       cp += len;
1265       if (strlen(cp) == 0)
1266         cp = NULL;
1267       else
1268         cp++;
1269
1270       if (item)
1271         silc_free(item);
1272     }
1273
1274     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1275       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1276       silc_free(payload->ke_grp_list);
1277       silc_free(payload);
1278       return SILC_SKE_STATUS_UNKNOWN_PKCS;
1279     }
1280   } else {
1281
1282     if (!rp->pkcs_alg_len) {
1283       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1284       silc_free(payload->ke_grp_list);
1285       silc_free(payload);
1286       return SILC_SKE_STATUS_BAD_PAYLOAD;
1287     }
1288
1289     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1290     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1291
1292     payload->pkcs_alg_len = rp->pkcs_alg_len;
1293     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1294   }
1295
1296   /* Get supported encryption algorithms */
1297   cp = rp->enc_alg_list;
1298   if (cp && strchr(cp, ',')) {
1299     while(cp) {
1300       char *item;
1301
1302       len = strcspn(cp, ",");
1303       item = silc_calloc(len + 1, sizeof(char));
1304       memcpy(item, cp, len);
1305
1306       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1307
1308       if (silc_cipher_is_supported(item) == TRUE) {
1309         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1310
1311         payload->enc_alg_len = len;
1312         payload->enc_alg_list = item;
1313         break;
1314       }
1315
1316       cp += len;
1317       if (strlen(cp) == 0)
1318         cp = NULL;
1319       else
1320         cp++;
1321
1322       if (item)
1323         silc_free(item);
1324     }
1325
1326     if (!payload->enc_alg_len && !payload->enc_alg_list) {
1327       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1328       silc_free(payload->ke_grp_list);
1329       silc_free(payload->pkcs_alg_list);
1330       silc_free(payload);
1331       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1332     }
1333   } else {
1334
1335     if (!rp->enc_alg_len) {
1336       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1337       silc_free(payload->ke_grp_list);
1338       silc_free(payload->pkcs_alg_list);
1339       silc_free(payload);
1340       return SILC_SKE_STATUS_BAD_PAYLOAD;
1341     }
1342
1343     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1344                     rp->enc_alg_list));
1345
1346     payload->enc_alg_len = rp->enc_alg_len;
1347     payload->enc_alg_list = strdup(rp->enc_alg_list);
1348   }
1349
1350   /* Get supported hash algorithms */
1351   cp = rp->hash_alg_list;
1352   if (cp && strchr(cp, ',')) {
1353     while(cp) {
1354       char *item;
1355
1356       len = strcspn(cp, ",");
1357       item = silc_calloc(len + 1, sizeof(char));
1358       memcpy(item, cp, len);
1359
1360       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1361
1362       if (silc_hash_is_supported(item) == TRUE) {
1363         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1364
1365         payload->hash_alg_len = len;
1366         payload->hash_alg_list = item;
1367         break;
1368       }
1369
1370       cp += len;
1371       if (strlen(cp) == 0)
1372         cp = NULL;
1373       else
1374         cp++;
1375
1376       if (item)
1377         silc_free(item);
1378     }
1379
1380     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1381       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1382       silc_free(payload->ke_grp_list);
1383       silc_free(payload->pkcs_alg_list);
1384       silc_free(payload->enc_alg_list);
1385       silc_free(payload);
1386       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1387     }
1388   } else {
1389
1390     if (!rp->hash_alg_len) {
1391       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1392       silc_free(payload->ke_grp_list);
1393       silc_free(payload->pkcs_alg_list);
1394       silc_free(payload->enc_alg_list);
1395       silc_free(payload);
1396       return SILC_SKE_STATUS_BAD_PAYLOAD;
1397     }
1398
1399     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1400                     rp->hash_alg_list));
1401
1402     payload->hash_alg_len = rp->hash_alg_len;
1403     payload->hash_alg_list = strdup(rp->hash_alg_list);
1404   }
1405
1406   /* Get supported HMACs */
1407   cp = rp->hmac_alg_list;
1408   if (cp && strchr(cp, ',')) {
1409     while(cp) {
1410       char *item;
1411
1412       len = strcspn(cp, ",");
1413       item = silc_calloc(len + 1, sizeof(char));
1414       memcpy(item, cp, len);
1415
1416       SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1417
1418       if (silc_hmac_is_supported(item) == TRUE) {
1419         SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1420
1421         payload->hmac_alg_len = len;
1422         payload->hmac_alg_list = item;
1423         break;
1424       }
1425
1426       cp += len;
1427       if (strlen(cp) == 0)
1428         cp = NULL;
1429       else
1430         cp++;
1431
1432       if (item)
1433         silc_free(item);
1434     }
1435
1436     if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1437       SILC_LOG_DEBUG(("Could not find supported HMAC"));
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_UNKNOWN_HMAC;
1444     }
1445   } else {
1446
1447     if (!rp->hmac_alg_len) {
1448       SILC_LOG_DEBUG(("HMAC not defined in payload"));
1449       silc_free(payload->ke_grp_list);
1450       silc_free(payload->pkcs_alg_list);
1451       silc_free(payload->enc_alg_list);
1452       silc_free(payload->hash_alg_list);
1453       silc_free(payload);
1454       return SILC_SKE_STATUS_BAD_PAYLOAD;
1455     }
1456
1457     SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1458                     rp->hmac_alg_list));
1459
1460     payload->hmac_alg_len = rp->hmac_alg_len;
1461     payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1462   }
1463
1464 #if 0
1465   /* Get supported compression algorithms */
1466   cp = rp->hash_alg_list;
1467   if (cp && strchr(cp, ',')) {
1468     while(cp) {
1469       char *item;
1470
1471       len = strcspn(cp, ",");
1472       item = silc_calloc(len + 1, sizeof(char));
1473       memcpy(item, cp, len);
1474
1475       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1476
1477       if (silc_hash_is_supported(item) == TRUE) {
1478         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1479
1480         payload->hash_alg_len = len;
1481         payload->hash_alg_list = item;
1482         break;
1483       }
1484
1485       cp += len;
1486       if (strlen(cp) == 0)
1487         cp = NULL;
1488       else
1489         cp++;
1490
1491       if (item)
1492         silc_free(item);
1493     }
1494
1495     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1496       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1497       silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1498       silc_free(payload->ke_grp_list);
1499       silc_free(payload->pkcs_alg_list);
1500       silc_free(payload->enc_alg_list);
1501       silc_free(payload);
1502       return;
1503     }
1504   } else {
1505
1506   }
1507 #endif
1508
1509   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1510     2 + payload->version_len + 
1511     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1512     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1513     2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1514
1515   return SILC_SKE_STATUS_OK;
1516 }
1517
1518 /* Creates random number such that 1 < rnd < n and at most length
1519    of len bits. The rnd sent as argument must be initialized. */
1520
1521 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, 
1522                                   uint32 len, 
1523                                   SilcMPInt *rnd)
1524 {
1525   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1526   unsigned char *string;
1527
1528   SILC_LOG_DEBUG(("Creating random number"));
1529
1530   /* Get the random number as string */
1531   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1532   if (!string)
1533     return SILC_SKE_STATUS_ERROR;
1534
1535   /* Decode the string into a MP integer */
1536   silc_mp_bin2mp(string, (len / 8), rnd);
1537   silc_mp_mod_2exp(rnd, rnd, len);
1538
1539   /* Checks */
1540   if (silc_mp_cmp_ui(rnd, 1) < 0)
1541     status = SILC_SKE_STATUS_ERROR;
1542
1543   if (silc_mp_cmp(rnd, n) >= 0)
1544     status = SILC_SKE_STATUS_ERROR;
1545
1546   memset(string, 'F', (len / 8));
1547   silc_free(string);
1548
1549   return status;
1550 }
1551
1552 /* Creates a hash value HASH as defined in the SKE protocol. If the
1553    `initiator' is TRUE then this function is used to create the HASH_i
1554    hash value defined in the protocol. If it is FALSE then this is used
1555    to create the HASH value defined by the protocol. */
1556
1557 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1558                                  unsigned char *return_hash,
1559                                  uint32 *return_hash_len,
1560                                  int initiator)
1561 {
1562   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1563   SilcBuffer buf;
1564   unsigned char *e, *f, *KEY;
1565   uint32 e_len, f_len, KEY_len;
1566   int ret;
1567
1568   SILC_LOG_DEBUG(("Start"));
1569
1570   if (initiator == FALSE) {
1571     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1572     f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1573     KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1574     
1575     buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1576                             ske->ke2_payload->pk_len + e_len + 
1577                             f_len + KEY_len);
1578     silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1579
1580     /* Format the buffer used to compute the hash value */
1581     ret = 
1582       silc_buffer_format(buf,
1583                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1584                                               ske->start_payload_copy->len),
1585                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1586                                               ske->ke2_payload->pk_len),
1587                          SILC_STR_UI_XNSTRING(e, e_len),
1588                          SILC_STR_UI_XNSTRING(f, f_len),
1589                          SILC_STR_UI_XNSTRING(KEY, KEY_len),
1590                          SILC_STR_END);
1591     if (ret == -1) {
1592       silc_buffer_free(buf);
1593       memset(e, 0, e_len);
1594       memset(f, 0, f_len);
1595       memset(KEY, 0, KEY_len);
1596       silc_free(e);
1597       silc_free(f);
1598       silc_free(KEY);
1599       return SILC_SKE_STATUS_ERROR;
1600     }
1601
1602     memset(e, 0, e_len);
1603     memset(f, 0, f_len);
1604     memset(KEY, 0, KEY_len);
1605     silc_free(e);
1606     silc_free(f);
1607     silc_free(KEY);
1608   } else {
1609     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1610
1611     buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1612                             ske->ke1_payload->pk_len + e_len);
1613     silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1614     
1615     /* Format the buffer used to compute the hash value */
1616     ret = 
1617       silc_buffer_format(buf,
1618                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1619                                               ske->start_payload_copy->len),
1620                          SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
1621                                               ske->ke1_payload->pk_len),
1622                          SILC_STR_UI_XNSTRING(e, e_len),
1623                          SILC_STR_END);
1624     if (ret == -1) {
1625       silc_buffer_free(buf);
1626       memset(e, 0, e_len);
1627       silc_free(e);
1628       return SILC_SKE_STATUS_ERROR;
1629     }
1630
1631     memset(e, 0, e_len);
1632     silc_free(e);
1633   }
1634
1635   /* Make the hash */
1636   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1637   *return_hash_len = ske->prop->hash->hash->hash_len;
1638
1639   if (initiator == FALSE) {
1640     SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1641   } else {
1642     SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1643   }
1644
1645   silc_buffer_free(buf);
1646
1647   return status;
1648 }
1649
1650 /* Processes the provided key material `data' as the SILC protocol 
1651    specification defines. */
1652
1653 SilcSKEStatus 
1654 silc_ske_process_key_material_data(unsigned char *data,
1655                                    uint32 data_len,
1656                                    uint32 req_iv_len,
1657                                    uint32 req_enc_key_len,
1658                                    uint32 req_hmac_key_len,
1659                                    SilcHash hash,
1660                                    SilcSKEKeyMaterial *key)
1661 {
1662   SilcBuffer buf;
1663   unsigned char hashd[32];
1664   uint32 hash_len = req_hmac_key_len;
1665   uint32 enc_key_len = req_enc_key_len / 8;
1666
1667   SILC_LOG_DEBUG(("Start"));
1668
1669   if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1670     return SILC_SKE_STATUS_ERROR;
1671
1672   buf = silc_buffer_alloc(1 + data_len);
1673   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1674   silc_buffer_format(buf,
1675                      SILC_STR_UI_CHAR(0),
1676                      SILC_STR_UI_XNSTRING(data, data_len),
1677                      SILC_STR_END);
1678
1679   /* Take IVs */
1680   memset(hashd, 0, sizeof(hashd));
1681   buf->data[0] = 0;
1682   silc_hash_make(hash, buf->data, buf->len, hashd);
1683   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1684   memcpy(key->send_iv, hashd, req_iv_len);
1685   memset(hashd, 0, sizeof(hashd));
1686   buf->data[0] = 1;
1687   silc_hash_make(hash, buf->data, buf->len, hashd);
1688   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1689   memcpy(key->receive_iv, hashd, req_iv_len);
1690   key->iv_len = req_iv_len;
1691
1692   /* Take the encryption keys. If requested key size is more than
1693      the size of hash length we will distribute more key material
1694      as protocol defines. */
1695   buf->data[0] = 2;
1696   if (enc_key_len > hash_len) {
1697     SilcBuffer dist;
1698     unsigned char k1[32], k2[32], k3[32];
1699     unsigned char *dtmp;
1700     
1701     /* XXX */
1702     if (enc_key_len > (3 * hash_len))
1703       return SILC_SKE_STATUS_ERROR;
1704     
1705     /* Take first round */
1706     memset(k1, 0, sizeof(k1));
1707     silc_hash_make(hash, buf->data, buf->len, k1);
1708     
1709     /* Take second round */
1710     dist = silc_buffer_alloc(data_len + hash_len);
1711     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1712     silc_buffer_format(dist,
1713                        SILC_STR_UI_XNSTRING(data, data_len),
1714                        SILC_STR_UI_XNSTRING(k1, hash_len),
1715                        SILC_STR_END);
1716     memset(k2, 0, sizeof(k2));
1717     silc_hash_make(hash, dist->data, dist->len, k2);
1718     
1719     /* Take third round */
1720     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1721     silc_buffer_pull_tail(dist, hash_len);
1722     silc_buffer_pull(dist, data_len + hash_len);
1723     silc_buffer_format(dist,
1724                        SILC_STR_UI_XNSTRING(k2, hash_len),
1725                        SILC_STR_END);
1726     silc_buffer_push(dist, data_len + hash_len);
1727     memset(k3, 0, sizeof(k3));
1728     silc_hash_make(hash, dist->data, dist->len, k3);
1729
1730     /* Then, save the keys */
1731     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1732     memcpy(dtmp, k1, hash_len);
1733     memcpy(dtmp + hash_len, k2, hash_len);
1734     memcpy(dtmp + hash_len, k3, hash_len);
1735
1736     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1737     memcpy(key->send_enc_key, dtmp, enc_key_len);
1738     key->enc_key_len = req_enc_key_len;
1739
1740     memset(dtmp, 0, (3 * hash_len));
1741     memset(k1, 0, sizeof(k1));
1742     memset(k2, 0, sizeof(k2));
1743     memset(k3, 0, sizeof(k3));
1744     silc_free(dtmp);
1745     silc_buffer_free(dist);
1746   } else {
1747     /* Take normal hash as key */
1748     memset(hashd, 0, sizeof(hashd));
1749     silc_hash_make(hash, buf->data, buf->len, hashd);
1750     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1751     memcpy(key->send_enc_key, hashd, enc_key_len);
1752     key->enc_key_len = req_enc_key_len;
1753   }
1754
1755   buf->data[0] = 3;
1756   if (enc_key_len > hash_len) {
1757     SilcBuffer dist;
1758     unsigned char k1[32], k2[32], k3[32];
1759     unsigned char *dtmp;
1760     
1761     /* XXX */
1762     if (enc_key_len > (3 * hash_len))
1763       return SILC_SKE_STATUS_ERROR;
1764     
1765     /* Take first round */
1766     memset(k1, 0, sizeof(k1));
1767     silc_hash_make(hash, buf->data, buf->len, k1);
1768     
1769     /* Take second round */
1770     dist = silc_buffer_alloc(data_len + hash_len);
1771     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1772     silc_buffer_format(dist,
1773                        SILC_STR_UI_XNSTRING(data, data_len),
1774                        SILC_STR_UI_XNSTRING(k1, hash_len),
1775                        SILC_STR_END);
1776     memset(k2, 0, sizeof(k2));
1777     silc_hash_make(hash, dist->data, dist->len, k2);
1778     
1779     /* Take third round */
1780     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1781     silc_buffer_pull_tail(dist, hash_len);
1782     silc_buffer_pull(dist, data_len + hash_len);
1783     silc_buffer_format(dist,
1784                        SILC_STR_UI_XNSTRING(k2, hash_len),
1785                        SILC_STR_END);
1786     silc_buffer_push(dist, data_len + hash_len);
1787     memset(k3, 0, sizeof(k3));
1788     silc_hash_make(hash, dist->data, dist->len, k3);
1789
1790     /* Then, save the keys */
1791     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1792     memcpy(dtmp, k1, hash_len);
1793     memcpy(dtmp + hash_len, k2, hash_len);
1794     memcpy(dtmp + hash_len, k3, hash_len);
1795
1796     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1797     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1798     key->enc_key_len = req_enc_key_len;
1799
1800     memset(dtmp, 0, (3 * hash_len));
1801     memset(k1, 0, sizeof(k1));
1802     memset(k2, 0, sizeof(k2));
1803     memset(k3, 0, sizeof(k3));
1804     silc_free(dtmp);
1805     silc_buffer_free(dist);
1806   } else {
1807     /* Take normal hash as key */
1808     memset(hashd, 0, sizeof(hashd));
1809     silc_hash_make(hash, buf->data, buf->len, hashd);
1810     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1811     memcpy(key->receive_enc_key, hashd, enc_key_len);
1812     key->enc_key_len = req_enc_key_len;
1813   }
1814
1815   /* Take HMAC key */
1816   memset(hashd, 0, sizeof(hashd));
1817   buf->data[0] = 4;
1818   silc_hash_make(hash, buf->data, buf->len, hashd);
1819   key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1820   memcpy(key->hmac_key, hashd, req_hmac_key_len);
1821   key->hmac_key_len = req_hmac_key_len;
1822
1823   silc_buffer_free(buf);
1824
1825   return SILC_SKE_STATUS_OK;
1826 }
1827
1828 /* Processes negotiated key material as protocol specifies. This returns
1829    the actual keys to be used in the SILC. */
1830
1831 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1832                                             uint32 req_iv_len,
1833                                             uint32 req_enc_key_len,
1834                                             uint32 req_hmac_key_len,
1835                                             SilcSKEKeyMaterial *key)
1836 {
1837   SilcSKEStatus status;
1838   SilcBuffer buf;
1839   unsigned char *tmpbuf;
1840   uint32 klen;
1841
1842   /* Encode KEY to binary data */
1843   tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1844
1845   buf = silc_buffer_alloc(klen + ske->hash_len);
1846   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1847   silc_buffer_format(buf,
1848                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
1849                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1850                      SILC_STR_END);
1851
1852   /* Process the key material */
1853   status = silc_ske_process_key_material_data(buf->data, buf->len,
1854                                               req_iv_len, req_enc_key_len,
1855                                               req_hmac_key_len, 
1856                                               ske->prop->hash, key);
1857
1858   memset(tmpbuf, 0, klen);
1859   silc_free(tmpbuf);
1860   silc_buffer_free(buf);
1861
1862   return status;
1863 }
1864
1865 /* Free key material structure */
1866
1867 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1868 {
1869   if (!key)
1870     return;
1871
1872   if (key->send_iv)
1873     silc_free(key->send_iv);
1874   if (key->receive_iv)
1875     silc_free(key->receive_iv);
1876   if (key->send_enc_key) {
1877     memset(key->send_enc_key, 0, key->enc_key_len / 8);
1878     silc_free(key->send_enc_key);
1879   }
1880   if (key->receive_enc_key) {
1881     memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1882     silc_free(key->receive_enc_key);
1883   }
1884   if (key->hmac_key) {
1885     memset(key->hmac_key, 0, key->hmac_key_len);
1886     silc_free(key->hmac_key);
1887   }
1888   silc_free(key);
1889 }