Code auditing weekend results and fixes committing.
[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 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 /* Allocates new SKE object. */
27
28 SilcSKE silc_ske_alloc()
29 {
30   SilcSKE ske;
31
32   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
33
34   ske = silc_calloc(1, sizeof(*ske));
35   ske->status = SILC_SKE_STATUS_OK;
36
37   return ske;
38 }
39
40 /* Free's SKE object. */
41
42 void silc_ske_free(SilcSKE ske)
43 {
44   SILC_LOG_DEBUG(("Freeing Key Exchange object"));
45
46   if (ske) {
47     /* Free start payload */
48     if (ske->start_payload)
49       silc_ske_payload_start_free(ske->start_payload);
50
51     /* Free KE1 payload */
52     if (ske->ke1_payload)
53       silc_ske_payload_one_free(ske->ke1_payload);
54
55     /* Free KE2 payload */
56     if (ske->ke2_payload)
57       silc_ske_payload_two_free(ske->ke2_payload);
58
59     /* Free rest */
60     if (ske->prop) {
61       if (ske->prop->group)
62         silc_free(ske->prop->group);
63       if (ske->prop->pkcs)
64         silc_pkcs_free(ske->prop->pkcs);
65       if (ske->prop->cipher)
66         silc_cipher_free(ske->prop->cipher);
67       if (ske->prop->hash)
68         silc_hash_free(ske->prop->hash);
69       silc_free(ske->prop);
70     }
71     if (ske->start_payload_copy)
72       silc_buffer_free(ske->start_payload_copy);
73     if (ske->pk)
74       silc_free(ske->pk);
75     if (ske->x) {
76       silc_mp_clear(ske->x);
77       silc_free(ske->x);
78     }
79     if (ske->KEY) {
80       silc_mp_clear(ske->KEY);
81       silc_free(ske->KEY);
82     }
83     if (ske->hash)
84       silc_free(ske->hash);
85     silc_free(ske);
86   }
87 }
88
89 /* Starts the SILC Key Exchange protocol for initiator. The connection
90    to the remote end must be established before calling this function
91    and the connecting socket must be sent as argument. This function
92    creates the Key Exchange Start Paload which includes all our
93    configured security properties. This payload is then sent to the
94    remote end for further processing. This payload must be sent as
95    argument to the function, however, it must not be encoded
96    already, it is done by this function.
97
98    The packet sending is done by calling a callback function. Caller
99    must provide a routine to send the packet. */
100
101 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
102                                        SilcSocketConnection sock,
103                                        SilcSKEStartPayload *start_payload,
104                                        SilcSKESendPacketCb send_packet,
105                                        void *context)
106 {
107   SilcSKEStatus status = SILC_SKE_STATUS_OK;
108   SilcBuffer payload_buf;
109
110   SILC_LOG_DEBUG(("Start"));
111
112   ske->sock = sock;
113   ske->rng = rng;
114
115   /* Encode the payload */
116   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
117   if (status != SILC_SKE_STATUS_OK)
118     return status;
119
120   /* Take a copy of the payload buffer for future use. It is used to
121      compute the HASH value. */
122   ske->start_payload_copy = silc_buffer_copy(payload_buf);
123
124   /* Send the packet. */
125   if (send_packet)
126     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
127
128   silc_buffer_free(payload_buf);
129
130   return status;
131 }
132
133 /* Function called after ske_initiator_start fuction. This receives
134    the remote ends Key Exchange Start payload which includes the
135    security properties selected by the responder from our payload
136    sent in the silc_ske_initiator_start function. */
137
138 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
139                                          SilcBuffer start_payload,
140                                          SilcSKECb callback,
141                                          void *context)
142 {
143   SilcSKEStatus status = SILC_SKE_STATUS_OK;
144   SilcSKEStartPayload *payload;
145   SilcSKESecurityProperties prop;
146   SilcSKEDiffieHellmanGroup group;
147
148   SILC_LOG_DEBUG(("Start"));
149
150   /* Decode the payload */
151   status = silc_ske_payload_start_decode(ske, start_payload, &payload);
152   if (status != SILC_SKE_STATUS_OK) {
153     ske->status = status;
154     return status;
155   }
156
157   /* Take the selected security properties into use while doing
158      the key exchange. This is used only while doing the key 
159      exchange. The same data is returned to upper levels by calling
160      the callback function. */
161   ske->prop = prop = silc_calloc(1, sizeof(*prop));
162   prop->flags = payload->flags;
163   status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
164   if (status != SILC_SKE_STATUS_OK)
165     goto err;
166
167   prop->group = group;
168
169   if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
170     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
171     goto err;
172   }
173
174   if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
175     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
176     goto err;
177   }
178
179   if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
180     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
181     goto err;
182   }
183
184   ske->start_payload = payload;
185
186   /* Return the received payload by calling the callback function. */
187   if (callback)
188     (*callback)(ske, context);
189
190   return status;
191
192  err:
193   if (payload)
194     silc_ske_payload_start_free(payload);
195
196   silc_free(group);
197
198   if (prop->pkcs)
199     silc_pkcs_free(prop->pkcs);
200   if (prop->cipher)
201     silc_cipher_free(prop->cipher);
202   if (prop->hash)
203     silc_hash_free(prop->hash);
204   silc_free(prop);
205   ske->prop = NULL;
206
207   if (status == SILC_SKE_STATUS_OK)
208     return SILC_SKE_STATUS_ERROR;
209
210   ske->status = status;
211   return status;
212 }
213
214 /* This function creates random number x, such that 1 < x < q and 
215    computes e = g ^ x mod p and sends the result to the remote end in 
216    Key Exchange 1 Payload. */
217
218 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
219                                          SilcPublicKey public_key,
220                                          SilcSKESendPacketCb send_packet,
221                                          void *context)
222 {
223   SilcSKEStatus status = SILC_SKE_STATUS_OK;
224   SilcBuffer payload_buf;
225   SilcInt *x, e;
226   SilcSKEOnePayload *payload;
227   unsigned int pk_len;
228
229   SILC_LOG_DEBUG(("Start"));
230
231   /* Create the random number x, 1 < x < q. */
232   x = silc_calloc(1, sizeof(*x));
233   silc_mp_init(x);
234   status = 
235     silc_ske_create_rnd(ske, ske->prop->group->group_order,
236                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
237                         x);
238   if (status != SILC_SKE_STATUS_OK) {
239     silc_mp_clear(x);
240     silc_free(x);
241     ske->status = status;
242     return status;
243   }
244
245   SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
246
247   /* Do the Diffie Hellman computation, e = g ^ x mod p */
248   silc_mp_init(&e);
249   silc_mp_powm(&e, &ske->prop->group->generator, x, 
250                &ske->prop->group->group);
251   
252   /* Encode the result to Key Exchange 1 Payload. */
253   payload = silc_calloc(1, sizeof(*payload));
254   payload->e = e;
255   payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
256   if (!payload->pk_data) {
257     silc_mp_clear(x);
258     silc_free(x);
259     silc_mp_clear(&e);
260     silc_free(payload);
261     ske->status = SILC_SKE_STATUS_OK;
262     return ske->status;
263   }
264   payload->pk_len = pk_len;
265   payload->pk_type = SILC_SKE_PK_TYPE_SILC;
266   status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
267   if (status != SILC_SKE_STATUS_OK) {
268     silc_mp_clear(x);
269     silc_free(x);
270     silc_mp_clear(&e);
271     silc_free(payload->pk_data);
272     silc_free(payload);
273     ske->status = status;
274     return status;
275   }
276
277   ske->ke1_payload = payload;
278   ske->x = x;
279
280   /* Send the packet. */
281   if (send_packet)
282     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
283
284   silc_buffer_free(payload_buf);
285
286   return status;
287 }
288
289 /* Receives Key Exchange 2 Payload from responder consisting responders
290    public key, f, and signature. This function verifies the public key,
291    computes the secret shared key and verifies the signature. */
292
293 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
294                                         SilcBuffer ke2_payload,
295                                         SilcSKEVerifyCb verify_key,
296                                         void *verify_context,
297                                         SilcSKECb callback,
298                                         void *context)
299 {
300   SilcSKEStatus status = SILC_SKE_STATUS_OK;
301   SilcSKETwoPayload *payload;
302   SilcPublicKey public_key = NULL;
303   SilcInt *KEY;
304   unsigned char hash[32];
305   unsigned int hash_len;
306
307   SILC_LOG_DEBUG(("Start"));
308
309   /* Decode the payload */
310   status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
311   if (status != SILC_SKE_STATUS_OK) {
312     ske->status = status;
313     return status;
314   }
315   ske->ke2_payload = payload;
316
317   SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
318
319   /* Compute the shared secret key */
320   KEY = silc_calloc(1, sizeof(*KEY));
321   silc_mp_init(KEY);
322   silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group);
323   ske->KEY = KEY;
324
325   SILC_LOG_DEBUG(("Verifying public key"));
326
327   if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, 
328                                    &public_key)) {
329     status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
330     goto err;
331   }
332
333   if (verify_key) {
334     status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
335                            payload->pk_type, verify_context);
336     if (status != SILC_SKE_STATUS_OK)
337       goto err;
338   }  
339
340   SILC_LOG_DEBUG(("Public key is authentic"));
341
342   /* Compute the hash value */
343   status = silc_ske_make_hash(ske, hash, &hash_len);
344   if (status != SILC_SKE_STATUS_OK)
345     goto err;
346
347   ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
348   memcpy(ske->hash, hash, hash_len);
349   ske->hash_len = hash_len;
350
351   SILC_LOG_DEBUG(("Verifying signature"));
352
353   /* Verify signature */
354   silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, 
355                                 public_key->pk_len);
356   if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
357                                     payload->sign_data, payload->sign_len,
358                                     hash, hash_len) == FALSE) {
359
360     SILC_LOG_DEBUG(("Signature don't match"));
361
362     status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
363     goto err;
364   }
365
366   SILC_LOG_DEBUG(("Signature is Ok"));
367
368   silc_pkcs_public_key_free(public_key);
369   memset(hash, 'F', hash_len);
370
371   /* Call the callback. */
372   if (callback)
373     (*callback)(ske, context);
374
375   return status;
376
377  err:
378   memset(hash, 'F', sizeof(hash));
379   silc_ske_payload_two_free(payload);
380   ske->ke2_payload = NULL;
381
382   silc_mp_clear(ske->KEY);
383   silc_free(ske->KEY);
384   ske->KEY = NULL;
385
386   if (public_key)
387     silc_pkcs_public_key_free(public_key);
388
389   if (ske->hash) {
390     memset(ske->hash, 'F', hash_len);
391     silc_free(ske->hash);
392     ske->hash = NULL;
393   }
394
395   if (status == SILC_SKE_STATUS_OK)
396     return SILC_SKE_STATUS_ERROR;
397
398   ske->status = status;
399   return status;
400 }
401
402 /* Starts Key Exchange protocol for responder. Responder receives
403    Key Exchange Start Payload from initiator consisting of all the
404    security properties the initiator supports. This function decodes
405    the payload and parses the payload further and selects the right 
406    security properties. */
407
408 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
409                                        SilcSocketConnection sock,
410                                        char *version,
411                                        SilcBuffer start_payload,
412                                        SilcSKECb callback,
413                                        void *context)
414 {
415   SilcSKEStatus status = SILC_SKE_STATUS_OK;
416   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
417
418   SILC_LOG_DEBUG(("Start"));
419
420   ske->sock = sock;
421   ske->rng = rng;
422
423   /* Decode the payload */
424   status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
425   if (status != SILC_SKE_STATUS_OK) {
426     ske->status = status;
427     return status;
428   }
429
430   /* Take a copy of the payload buffer for future use. It is used to
431      compute the HASH value. */
432   ske->start_payload_copy = silc_buffer_copy(start_payload);
433
434   /* Parse and select the security properties from the payload */
435   payload = silc_calloc(1, sizeof(*payload));
436   status = silc_ske_select_security_properties(ske, version,
437                                                payload, remote_payload);
438   if (status != SILC_SKE_STATUS_OK)
439     goto err;
440
441   ske->start_payload = payload;
442
443   /* Call the callback function. */
444   if (callback)
445     (*callback)(ske, context);
446
447   return status;
448
449  err:
450   if (remote_payload)
451     silc_ske_payload_start_free(remote_payload);
452   if (payload)
453     silc_free(payload);
454
455   if (status == SILC_SKE_STATUS_OK)
456     return SILC_SKE_STATUS_ERROR;
457
458   ske->status = status;
459   return status;
460 }
461
462 /* The selected security properties from the initiator payload is now 
463    encoded into Key Exchange Start Payload and sent to the initiator. */
464
465 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
466                                          SilcSKEStartPayload *start_payload,
467                                          SilcSKESendPacketCb send_packet,
468                                          void *context)
469 {
470   SilcSKEStatus status = SILC_SKE_STATUS_OK;
471   SilcBuffer payload_buf;
472   SilcSKESecurityProperties prop;
473   SilcSKEDiffieHellmanGroup group = NULL;
474
475   SILC_LOG_DEBUG(("Start"));
476
477   /* Allocate security properties from the payload. These are allocated
478      only for this negotiation and will be free'd after KE is over. */
479   ske->prop = prop = silc_calloc(1, sizeof(*prop));
480   prop->flags = start_payload->flags;
481   status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
482   if (status != SILC_SKE_STATUS_OK)
483     goto err;
484
485   prop->group = group;
486
487   if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
488                       &prop->pkcs) == FALSE) {
489     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
490     goto err;
491   }
492
493   if (silc_cipher_alloc(start_payload->enc_alg_list, 
494                         &prop->cipher) == FALSE) {
495     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
496     goto err;
497   }
498
499   if (silc_hash_alloc(start_payload->hash_alg_list,
500                       &prop->hash) == FALSE) {
501     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
502     goto err;
503   }
504
505   /* Encode the payload */
506   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
507   if (status != SILC_SKE_STATUS_OK)
508     goto err;
509
510   /* Send the packet. */
511   if (send_packet)
512     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
513
514   silc_buffer_free(payload_buf);
515
516   return status;
517
518  err:
519   if (group)
520     silc_free(group);
521
522   if (prop->pkcs)
523     silc_pkcs_free(prop->pkcs);
524   if (prop->cipher)
525     silc_cipher_free(prop->cipher);
526   if (prop->hash)
527     silc_hash_free(prop->hash);
528   silc_free(prop);
529   ske->prop = NULL;
530
531   if (status == SILC_SKE_STATUS_OK)
532     return SILC_SKE_STATUS_ERROR;
533
534   ske->status = status;
535   return status;
536 }
537
538 /* This function receives the Key Exchange 1 Payload from the initiator.
539    After processing the payload this then selects random number x,
540    such that 1 < x < q and computes f = g ^ x mod p. This then puts
541    the result f to a Key Exchange 2 Payload which is later processed
542    in ske_responder_finish function. The callback function should
543    not touch the payload (it should merely call the ske_responder_finish
544    function). */
545
546 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
547                                          SilcBuffer ke1_payload,
548                                          SilcSKECb callback,
549                                          void *context)
550 {
551   SilcSKEStatus status = SILC_SKE_STATUS_OK;
552   SilcSKEOnePayload *one_payload;
553   SilcSKETwoPayload *two_payload;
554   SilcInt *x, f;
555
556   SILC_LOG_DEBUG(("Start"));
557
558   /* Decode Key Exchange 1 Payload */
559   status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
560   if (status != SILC_SKE_STATUS_OK) {
561     ske->status = status;
562     return status;
563   }
564
565   /* Create the random number x, 1 < x < q. */
566   x = silc_calloc(1, sizeof(*x));
567   silc_mp_init(x);
568   status = 
569     silc_ske_create_rnd(ske, ske->prop->group->group_order,
570                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
571                         x);
572   if (status != SILC_SKE_STATUS_OK) {
573     silc_mp_clear(x);
574     silc_free(x);
575     return status;
576   }
577
578   SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
579
580   /* Do the Diffie Hellman computation, f = g ^ x mod p */
581   silc_mp_init(&f);
582   silc_mp_powm(&f, &ske->prop->group->generator, x, 
583                &ske->prop->group->group);
584   
585   /* Save the results for later processing */
586   two_payload = silc_calloc(1, sizeof(*two_payload));
587   two_payload->f = f;
588   ske->x = x;
589   ske->ke1_payload = one_payload;
590   ske->ke2_payload = two_payload;
591
592   /* Call the callback. */
593   if (callback)
594     (*callback)(ske, context);
595
596   return status;
597 }
598
599 /* This function computes the secret shared key KEY = e ^ x mod p, and, 
600    a hash value to be signed and sent to the other end. This then
601    encodes Key Exchange 2 Payload and sends it to the other end. */
602
603 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
604                                         SilcPublicKey public_key,
605                                         SilcPrivateKey private_key,
606                                         SilcSKEPKType pk_type,
607                                         SilcSKESendPacketCb send_packet,
608                                         void *context)
609 {
610   SilcSKEStatus status = SILC_SKE_STATUS_OK;
611   SilcBuffer payload_buf;
612   SilcInt *KEY;
613   unsigned char hash[32], sign[256], *pk;
614   unsigned int hash_len, sign_len, pk_len;
615
616   SILC_LOG_DEBUG(("Start"));
617
618   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
619
620   /* Compute the shared secret key */
621   KEY = silc_calloc(1, sizeof(*KEY));
622   silc_mp_init(KEY);
623   silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x, 
624                &ske->prop->group->group);
625   ske->KEY = KEY;
626
627   SILC_LOG_DEBUG(("Getting public key"));
628
629   /* Get the public key */
630   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
631   if (!pk) {
632     status = SILC_SKE_STATUS_ERROR;
633     goto err;
634   }
635   ske->ke2_payload->pk_data = pk;
636   ske->ke2_payload->pk_len = pk_len;
637   ske->ke2_payload->pk_type = pk_type;
638
639   SILC_LOG_DEBUG(("Computing HASH value"));
640
641   /* Compute the hash value */
642   memset(hash, 0, sizeof(hash));
643   status = silc_ske_make_hash(ske, hash, &hash_len);
644   if (status != SILC_SKE_STATUS_OK)
645     goto err;
646
647   ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
648   memcpy(ske->hash, hash, hash_len);
649   ske->hash_len = hash_len;
650
651   SILC_LOG_DEBUG(("Signing HASH value"));
652
653   /* Sign the hash value */
654   silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
655                                  private_key->prv_len);
656   ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
657                               hash, hash_len,
658                               sign, &sign_len);
659   ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
660   memcpy(ske->ke2_payload->sign_data, sign, sign_len);
661   memset(sign, 0, sizeof(sign));
662   ske->ke2_payload->sign_len = sign_len;
663
664   /* Encode the Key Exchange 2 Payload */
665   status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
666                                        &payload_buf);
667   if (status != SILC_SKE_STATUS_OK)
668     goto err;
669
670   /* Send the packet. */
671   if (send_packet)
672     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
673
674   silc_buffer_free(payload_buf);
675
676   return status;
677
678  err:
679   silc_mp_clear(ske->KEY);
680   silc_free(ske->KEY);
681   ske->KEY = NULL;
682   silc_ske_payload_two_free(ske->ke2_payload);
683
684   if (status == SILC_SKE_STATUS_OK)
685     return SILC_SKE_STATUS_ERROR;
686
687   ske->status = status;
688   return status;
689 }
690
691 /* The Key Exchange protocol is ended by calling this function. This
692    must not be called until the keys are processed like the protocol
693    defines. This function is for both initiator and responder. */
694
695 SilcSKEStatus silc_ske_end(SilcSKE ske,
696                            SilcSKESendPacketCb send_packet,
697                            void *context)
698 {
699   SilcBuffer packet;
700
701   SILC_LOG_DEBUG(("Start"));
702
703   packet = silc_buffer_alloc(4);
704   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
705   silc_buffer_format(packet,
706                      SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
707                      SILC_STR_END);
708
709   if (send_packet)
710     (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
711
712   silc_buffer_free(packet);
713
714   return SILC_SKE_STATUS_OK;
715 }
716
717 /* Aborts the Key Exchange protocol. This is called if error occurs
718    while performing the protocol. The status argument is the error
719    status and it is sent to the remote end. */
720
721 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
722                              SilcSKESendPacketCb send_packet,
723                              void *context)
724 {
725   SilcBuffer packet;
726
727   SILC_LOG_DEBUG(("Start"));
728
729   packet = silc_buffer_alloc(4);
730   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
731   silc_buffer_format(packet,
732                      SILC_STR_UI_SHORT(status),
733                      SILC_STR_END);
734
735   if (send_packet)
736     (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
737
738   silc_buffer_free(packet);
739
740   return SILC_SKE_STATUS_OK;
741 }
742
743 /* Assembles security properties to Key Exchange Start Payload to be
744    sent to the remote end. This checks system wide (SILC system, that is)
745    settings and chooses from those. However, if other properties
746    should be used this function is easy to replace by another function,
747    as, this function is called by the caller of the protocol and not
748    by the protocol itself. */
749
750 SilcSKEStatus 
751 silc_ske_assemble_security_properties(SilcSKE ske,
752                                       unsigned char flags,
753                                       char *version,
754                                       SilcSKEStartPayload **return_payload)
755 {
756   SilcSKEStartPayload *rp;
757   int i;
758
759   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
760
761   rp = silc_calloc(1, sizeof(*rp));
762
763   /* Set flags */
764   rp->flags = flags;
765
766   /* Set random cookie */
767   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
768   for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
769     rp->cookie[i] = silc_rng_get_byte(ske->rng);
770   rp->cookie_len = SILC_SKE_COOKIE_LEN;
771
772   /* Put version */
773   rp->version = strdup(version);
774   rp->version_len = strlen(version);
775
776   /* Get supported Key Exhange groups */
777   rp->ke_grp_list = silc_ske_get_supported_groups();
778   rp->ke_grp_len = strlen(rp->ke_grp_list);
779
780   /* Get supported PKCS algorithms */
781   rp->pkcs_alg_list = silc_pkcs_get_supported();
782   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
783
784   /* Get supported encryption algorithms */
785   rp->enc_alg_list = silc_cipher_get_supported();
786   rp->enc_alg_len = strlen(rp->enc_alg_list);
787
788   /* Get supported hash algorithms */
789   rp->hash_alg_list = silc_hash_get_supported();
790   rp->hash_alg_len = strlen(rp->hash_alg_list);
791
792   /* XXX */
793   /* Get supported compression algorithms */
794   rp->comp_alg_list = "";
795   rp->comp_alg_len = 0;
796
797   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
798     2 + rp->version_len +
799     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
800     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
801     2 + rp->comp_alg_len;
802
803   *return_payload = rp;
804
805   return SILC_SKE_STATUS_OK;
806 }
807
808 /* Selects the supported security properties from the remote end's Key 
809    Exchange Start Payload. */
810
811 SilcSKEStatus 
812 silc_ske_select_security_properties(SilcSKE ske,
813                                     char *version,
814                                     SilcSKEStartPayload *payload,
815                                     SilcSKEStartPayload *remote_payload)
816 {
817   SilcSKEStatus status;
818   SilcSKEStartPayload *rp;
819   char *cp;
820   int len;
821
822   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
823
824   rp = remote_payload;
825
826   /* Check version string */
827   status = silc_ske_check_version(ske, rp->version, rp->version_len);
828   if (status != SILC_SKE_STATUS_OK) {
829     ske->status = status;
830     return status;
831   }
832
833   /* Flags are returned unchanged. */
834   payload->flags = rp->flags;
835
836   /* Take cookie */
837   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
838   payload->cookie_len = SILC_SKE_COOKIE_LEN;
839   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
840
841   /* Put our version to our reply */
842   payload->version = strdup(version);
843   payload->version_len = strlen(version);
844
845   /* Get supported Key Exchange groups */
846   cp = rp->ke_grp_list;
847   if (cp && strchr(cp, ',')) {
848     while(cp) {
849       char *item;
850
851       len = strcspn(cp, ",");
852       item = silc_calloc(len + 1, sizeof(char));
853       memcpy(item, cp, len);
854
855       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
856
857       if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
858         SILC_LOG_DEBUG(("Found KE group `%s'", item));
859
860         payload->ke_grp_len = len;
861         payload->ke_grp_list = item;
862         break;
863       }
864
865       cp += len;
866       if (strlen(cp) == 0)
867         cp = NULL;
868       else
869         cp++;
870
871       if (item)
872         silc_free(item);
873     }
874
875     if (!payload->ke_grp_len && !payload->ke_grp_list) {
876       SILC_LOG_DEBUG(("Could not find supported KE group"));
877       silc_free(payload);
878       return SILC_SKE_STATUS_UNKNOWN_GROUP;
879     }
880   } else {
881
882     if (!rp->ke_grp_len) {
883       SILC_LOG_DEBUG(("KE group not defined in payload"));
884       silc_free(payload);
885       return SILC_SKE_STATUS_BAD_PAYLOAD;
886     }
887
888     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
889     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
890
891     payload->ke_grp_len = rp->ke_grp_len;
892     payload->ke_grp_list = strdup(rp->ke_grp_list);
893   }
894
895   /* Get supported PKCS algorithms */
896   cp = rp->pkcs_alg_list;
897   if (cp && strchr(cp, ',')) {
898     while(cp) {
899       char *item;
900
901       len = strcspn(cp, ",");
902       item = silc_calloc(len + 1, sizeof(char));
903       memcpy(item, cp, len);
904
905       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
906
907       if (silc_pkcs_is_supported(item) == TRUE) {
908         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
909
910         payload->pkcs_alg_len = len;
911         payload->pkcs_alg_list = item;
912         break;
913       }
914
915       cp += len;
916       if (strlen(cp) == 0)
917         cp = NULL;
918       else
919         cp++;
920
921       if (item)
922         silc_free(item);
923     }
924
925     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
926       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
927       silc_free(payload->ke_grp_list);
928       silc_free(payload);
929       return SILC_SKE_STATUS_UNKNOWN_PKCS;
930     }
931   } else {
932
933     if (!rp->pkcs_alg_len) {
934       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
935       silc_free(payload->ke_grp_list);
936       silc_free(payload);
937       return SILC_SKE_STATUS_BAD_PAYLOAD;
938     }
939
940     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
941     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
942
943     payload->pkcs_alg_len = rp->pkcs_alg_len;
944     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
945   }
946
947   /* Get supported encryption algorithms */
948   cp = rp->enc_alg_list;
949   if (cp && strchr(cp, ',')) {
950     while(cp) {
951       char *item;
952
953       len = strcspn(cp, ",");
954       item = silc_calloc(len + 1, sizeof(char));
955       memcpy(item, cp, len);
956
957       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
958
959       if (silc_cipher_is_supported(item) == TRUE) {
960         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
961
962         payload->enc_alg_len = len;
963         payload->enc_alg_list = item;
964         break;
965       }
966
967       cp += len;
968       if (strlen(cp) == 0)
969         cp = NULL;
970       else
971         cp++;
972
973       if (item)
974         silc_free(item);
975     }
976
977     if (!payload->enc_alg_len && !payload->enc_alg_list) {
978       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
979       silc_free(payload->ke_grp_list);
980       silc_free(payload->pkcs_alg_list);
981       silc_free(payload);
982       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
983     }
984   } else {
985
986     if (!rp->enc_alg_len) {
987       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
988       silc_free(payload->ke_grp_list);
989       silc_free(payload->pkcs_alg_list);
990       silc_free(payload);
991       return SILC_SKE_STATUS_BAD_PAYLOAD;
992     }
993
994     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
995                     rp->enc_alg_list));
996
997     payload->enc_alg_len = rp->enc_alg_len;
998     payload->enc_alg_list = strdup(rp->enc_alg_list);
999   }
1000
1001   /* Get supported hash algorithms */
1002   cp = rp->hash_alg_list;
1003   if (cp && strchr(cp, ',')) {
1004     while(cp) {
1005       char *item;
1006
1007       len = strcspn(cp, ",");
1008       item = silc_calloc(len + 1, sizeof(char));
1009       memcpy(item, cp, len);
1010
1011       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1012
1013       if (silc_hash_is_supported(item) == TRUE) {
1014         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1015
1016         payload->hash_alg_len = len;
1017         payload->hash_alg_list = item;
1018         break;
1019       }
1020
1021       cp += len;
1022       if (strlen(cp) == 0)
1023         cp = NULL;
1024       else
1025         cp++;
1026
1027       if (item)
1028         silc_free(item);
1029     }
1030
1031     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1032       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1033       silc_free(payload->ke_grp_list);
1034       silc_free(payload->pkcs_alg_list);
1035       silc_free(payload->enc_alg_list);
1036       silc_free(payload);
1037       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1038     }
1039   } else {
1040
1041     if (!rp->hash_alg_len) {
1042       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1043       silc_free(payload->ke_grp_list);
1044       silc_free(payload->pkcs_alg_list);
1045       silc_free(payload->enc_alg_list);
1046       silc_free(payload);
1047       return SILC_SKE_STATUS_BAD_PAYLOAD;
1048     }
1049
1050     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1051                     rp->hash_alg_list));
1052
1053     payload->hash_alg_len = rp->hash_alg_len;
1054     payload->hash_alg_list = strdup(rp->hash_alg_list);
1055   }
1056
1057 #if 0
1058   /* Get supported compression algorithms */
1059   cp = rp->hash_alg_list;
1060   if (cp && strchr(cp, ',')) {
1061     while(cp) {
1062       char *item;
1063
1064       len = strcspn(cp, ",");
1065       item = silc_calloc(len + 1, sizeof(char));
1066       memcpy(item, cp, len);
1067
1068       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1069
1070       if (silc_hash_is_supported(item) == TRUE) {
1071         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1072
1073         payload->hash_alg_len = len;
1074         payload->hash_alg_list = item;
1075         break;
1076       }
1077
1078       cp += len;
1079       if (strlen(cp) == 0)
1080         cp = NULL;
1081       else
1082         cp++;
1083
1084       if (item)
1085         silc_free(item);
1086     }
1087
1088     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1089       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1090       silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1091       silc_free(payload->ke_grp_list);
1092       silc_free(payload->pkcs_alg_list);
1093       silc_free(payload->enc_alg_list);
1094       silc_free(payload);
1095       return;
1096     }
1097   } else {
1098
1099   }
1100 #endif
1101
1102   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1103     2 + payload->version_len + 
1104     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1105     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1106     2 + payload->comp_alg_len;
1107
1108   return SILC_SKE_STATUS_OK;
1109 }
1110
1111 /* Creates random number such that 1 < rnd < n and at most length
1112    of len bits. The rnd sent as argument must be initialized. */
1113
1114 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
1115                                   unsigned int len, 
1116                                   SilcInt *rnd)
1117 {
1118   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1119   unsigned char *string;
1120
1121   SILC_LOG_DEBUG(("Creating random number"));
1122
1123   /* Get the random number as string */
1124   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1125   if (!string)
1126     return SILC_SKE_STATUS_ERROR;
1127
1128   /* Decode the string into a MP integer */
1129   silc_mp_bin2mp(string, (len / 8), rnd);
1130   silc_mp_mod_2exp(rnd, rnd, len);
1131
1132   /* Checks */
1133   if (silc_mp_cmp_ui(rnd, 1) < 0)
1134     status = SILC_SKE_STATUS_ERROR;
1135
1136   if (silc_mp_cmp(rnd, &n) >= 0)
1137     status = SILC_SKE_STATUS_ERROR;
1138
1139   memset(string, 'F', (len / 8));
1140   silc_free(string);
1141
1142   return status;
1143 }
1144
1145 /* Creates a hash value HASH as defined in the SKE protocol. */
1146
1147 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1148                                  unsigned char *return_hash,
1149                                  unsigned int *return_hash_len)
1150 {
1151   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1152   SilcBuffer buf;
1153   unsigned char *e, *f, *KEY;
1154   unsigned int e_len, f_len, KEY_len;
1155   int ret;
1156
1157   SILC_LOG_DEBUG(("Start"));
1158
1159   e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1160   f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1161   KEY = silc_mp_mp2bin(ske->KEY, &KEY_len);
1162
1163   buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1164                           ske->pk_len + e_len + f_len + KEY_len);
1165   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1166
1167   /* Format the buffer used to compute the hash value */
1168   ret = silc_buffer_format(buf,
1169                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1170                                                 ske->start_payload_copy->len),
1171                            SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1172                            SILC_STR_UI_XNSTRING(e, e_len),
1173                            SILC_STR_UI_XNSTRING(f, f_len),
1174                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
1175                            SILC_STR_END);
1176   if (ret == -1) {
1177     silc_buffer_free(buf);
1178     memset(e, 0, e_len);
1179     memset(f, 0, f_len);
1180     memset(KEY, 0, KEY_len);
1181     silc_free(e);
1182     silc_free(f);
1183     silc_free(KEY);
1184     return SILC_SKE_STATUS_ERROR;
1185   }
1186
1187   /* Make the hash */
1188   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1189   *return_hash_len = ske->prop->hash->hash->hash_len;
1190
1191   SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1192
1193   silc_buffer_free(buf);
1194   memset(e, 0, e_len);
1195   memset(f, 0, f_len);
1196   memset(KEY, 0, KEY_len);
1197   silc_free(e);
1198   silc_free(f);
1199   silc_free(KEY);
1200
1201   return status;
1202 }
1203
1204 /* Processes negotiated key material as protocol specifies. This returns
1205    the actual keys to be used in the SILC. */
1206
1207 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1208                                             unsigned int req_iv_len,
1209                                             unsigned int req_enc_key_len,
1210                                             unsigned int req_hmac_key_len,
1211                                             SilcSKEKeyMaterial *key)
1212 {
1213   int klen;
1214   SilcBuffer buf;
1215   unsigned char *tmpbuf;
1216   unsigned char hash[32];
1217   unsigned int hash_len = ske->prop->hash->hash->hash_len;
1218   unsigned int enc_key_len = req_enc_key_len / 8;
1219   int ret;
1220
1221   SILC_LOG_DEBUG(("Start"));
1222
1223   /* Encode KEY to binary data */
1224   tmpbuf = silc_mp_mp2bin(ske->KEY, &klen);
1225
1226   buf = silc_buffer_alloc(1 + klen + hash_len);
1227   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1228   ret = silc_buffer_format(buf,
1229                            SILC_STR_UI_CHAR(0),
1230                            SILC_STR_UI_XNSTRING(tmpbuf, klen),
1231                            SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1232                            SILC_STR_END);
1233   if (ret == -1) {
1234     memset(tmpbuf, 0, klen);
1235     silc_free(tmpbuf);
1236     silc_buffer_free(buf);
1237     return SILC_SKE_STATUS_ERROR;
1238   }
1239
1240   /* Take IVs */
1241   memset(hash, 0, sizeof(hash));
1242   buf->data[0] = 0;
1243   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1244   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1245   memcpy(key->send_iv, hash, req_iv_len);
1246   memset(hash, 0, sizeof(hash));
1247   buf->data[0] = 1;
1248   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1249   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1250   memcpy(key->receive_iv, hash, req_iv_len);
1251   key->iv_len = req_iv_len;
1252
1253   /* Take the encryption keys. If requested key size is more than
1254      the size of hash length we will distribute more key material
1255      as protocol defines. */
1256   buf->data[0] = 2;
1257   if (enc_key_len > hash_len) {
1258     SilcBuffer dist;
1259     unsigned char k1[32], k2[32], k3[32];
1260     unsigned char *dtmp;
1261     
1262     /* XXX */
1263     if (enc_key_len > (3 * hash_len))
1264       return SILC_SKE_STATUS_ERROR;
1265     
1266     memset(k1, 0, sizeof(k1));
1267     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1268     
1269     /* XXX */
1270     dist = silc_buffer_alloc(hash_len * 3);
1271     
1272     silc_buffer_pull_tail(dist, klen + hash_len);
1273     silc_buffer_format(dist,
1274                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1275                        SILC_STR_UI_XNSTRING(k1, hash_len),
1276                        SILC_STR_END);
1277     
1278     memset(k2, 0, sizeof(k2));
1279     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1280     
1281     silc_buffer_pull(dist, klen + hash_len);
1282     silc_buffer_format(dist,
1283                        SILC_STR_UI_XNSTRING(k2, hash_len),
1284                        SILC_STR_END);
1285     silc_buffer_push(dist, klen + hash_len);
1286     
1287     memset(k3, 0, sizeof(k3));
1288     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1289     
1290     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1291     memcpy(dtmp, k1, hash_len);
1292     memcpy(dtmp + hash_len, k2, hash_len);
1293     memcpy(dtmp + hash_len, k3, hash_len);
1294
1295     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1296     memcpy(key->send_enc_key, dtmp, enc_key_len);
1297     key->enc_key_len = req_enc_key_len;
1298
1299     memset(dtmp, 0, (3 * hash_len));
1300     memset(k1, 0, sizeof(k1));
1301     memset(k2, 0, sizeof(k2));
1302     memset(k3, 0, sizeof(k3));
1303     silc_free(dtmp);
1304     silc_buffer_free(dist);
1305   } else {
1306     /* Take normal hash as key */
1307     memset(hash, 0, sizeof(hash));
1308     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1309     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1310     memcpy(key->send_enc_key, hash, enc_key_len);
1311     key->enc_key_len = req_enc_key_len;
1312   }
1313
1314   buf->data[0] = 3;
1315   if (enc_key_len > hash_len) {
1316     SilcBuffer dist;
1317     unsigned char k1[32], k2[32], k3[32];
1318     unsigned char *dtmp;
1319     
1320     /* XXX */
1321     if (enc_key_len > (3 * hash_len))
1322       return SILC_SKE_STATUS_ERROR;
1323     
1324     memset(k1, 0, sizeof(k1));
1325     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1326     
1327     /* XXX */
1328     dist = silc_buffer_alloc(hash_len * 3);
1329     
1330     silc_buffer_pull_tail(dist, klen + hash_len);
1331     silc_buffer_format(dist,
1332                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1333                        SILC_STR_UI_XNSTRING(k1, hash_len),
1334                        SILC_STR_END);
1335     
1336     memset(k2, 0, sizeof(k2));
1337     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1338     
1339     silc_buffer_pull(dist, klen + hash_len);
1340     silc_buffer_format(dist,
1341                        SILC_STR_UI_XNSTRING(k2, hash_len),
1342                        SILC_STR_END);
1343     silc_buffer_push(dist, klen + hash_len);
1344     
1345     memset(k3, 0, sizeof(k3));
1346     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1347     
1348     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1349     memcpy(dtmp, k1, hash_len);
1350     memcpy(dtmp + hash_len, k2, hash_len);
1351     memcpy(dtmp + hash_len, k3, hash_len);
1352
1353     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1354     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1355     key->enc_key_len = req_enc_key_len;
1356
1357     memset(dtmp, 0, (3 * hash_len));
1358     memset(k1, 0, sizeof(k1));
1359     memset(k2, 0, sizeof(k2));
1360     memset(k3, 0, sizeof(k3));
1361     silc_free(dtmp);
1362     silc_buffer_free(dist);
1363   } else {
1364     /* Take normal hash as key */
1365     memset(hash, 0, sizeof(hash));
1366     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1367     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1368     memcpy(key->receive_enc_key, hash, enc_key_len);
1369     key->enc_key_len = req_enc_key_len;
1370   }
1371
1372   /* Take HMAC key */
1373   memset(hash, 0, sizeof(hash));
1374   buf->data[0] = 4;
1375   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1376   key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1377   memcpy(key->hmac_key, hash, req_hmac_key_len);
1378   key->hmac_key_len = req_hmac_key_len;
1379
1380   memset(tmpbuf, 0, klen);
1381   silc_free(tmpbuf);
1382
1383   return SILC_SKE_STATUS_OK;
1384 }