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 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 (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data, 
357                        payload->sign_len, hash, hash_len) == FALSE) {
358
359     SILC_LOG_DEBUG(("Signature don't match"));
360
361     status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
362     goto err;
363   }
364
365   SILC_LOG_DEBUG(("Signature is Ok"));
366
367   silc_pkcs_public_key_free(public_key);
368   memset(hash, 'F', hash_len);
369
370   /* Call the callback. */
371   if (callback)
372     (*callback)(ske, context);
373
374   return status;
375
376  err:
377   memset(hash, 'F', sizeof(hash));
378   silc_ske_payload_two_free(payload);
379   ske->ke2_payload = NULL;
380
381   silc_mp_clear(ske->KEY);
382   silc_free(ske->KEY);
383   ske->KEY = NULL;
384
385   if (public_key)
386     silc_pkcs_public_key_free(public_key);
387
388   if (ske->hash) {
389     memset(ske->hash, 'F', hash_len);
390     silc_free(ske->hash);
391     ske->hash = NULL;
392   }
393
394   if (status == SILC_SKE_STATUS_OK)
395     return SILC_SKE_STATUS_ERROR;
396
397   ske->status = status;
398   return status;
399 }
400
401 /* Starts Key Exchange protocol for responder. Responder receives
402    Key Exchange Start Payload from initiator consisting of all the
403    security properties the initiator supports. This function decodes
404    the payload and parses the payload further and selects the right 
405    security properties. */
406
407 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
408                                        SilcSocketConnection sock,
409                                        char *version,
410                                        SilcBuffer start_payload,
411                                        SilcSKECb callback,
412                                        void *context)
413 {
414   SilcSKEStatus status = SILC_SKE_STATUS_OK;
415   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
416
417   SILC_LOG_DEBUG(("Start"));
418
419   ske->sock = sock;
420   ske->rng = rng;
421
422   /* Decode the payload */
423   status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
424   if (status != SILC_SKE_STATUS_OK) {
425     ske->status = status;
426     return status;
427   }
428
429   /* Take a copy of the payload buffer for future use. It is used to
430      compute the HASH value. */
431   ske->start_payload_copy = silc_buffer_copy(start_payload);
432
433   /* Parse and select the security properties from the payload */
434   payload = silc_calloc(1, sizeof(*payload));
435   status = silc_ske_select_security_properties(ske, version,
436                                                payload, remote_payload);
437   if (status != SILC_SKE_STATUS_OK)
438     goto err;
439
440   ske->start_payload = payload;
441
442   /* Call the callback function. */
443   if (callback)
444     (*callback)(ske, context);
445
446   return status;
447
448  err:
449   if (remote_payload)
450     silc_ske_payload_start_free(remote_payload);
451   if (payload)
452     silc_free(payload);
453
454   if (status == SILC_SKE_STATUS_OK)
455     return SILC_SKE_STATUS_ERROR;
456
457   ske->status = status;
458   return status;
459 }
460
461 /* The selected security properties from the initiator payload is now 
462    encoded into Key Exchange Start Payload and sent to the initiator. */
463
464 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
465                                          SilcSKEStartPayload *start_payload,
466                                          SilcSKESendPacketCb send_packet,
467                                          void *context)
468 {
469   SilcSKEStatus status = SILC_SKE_STATUS_OK;
470   SilcBuffer payload_buf;
471   SilcSKESecurityProperties prop;
472   SilcSKEDiffieHellmanGroup group = NULL;
473
474   SILC_LOG_DEBUG(("Start"));
475
476   /* Allocate security properties from the payload. These are allocated
477      only for this negotiation and will be free'd after KE is over. */
478   ske->prop = prop = silc_calloc(1, sizeof(*prop));
479   prop->flags = start_payload->flags;
480   status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
481   if (status != SILC_SKE_STATUS_OK)
482     goto err;
483
484   prop->group = group;
485
486   if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
487                       &prop->pkcs) == FALSE) {
488     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
489     goto err;
490   }
491
492   if (silc_cipher_alloc(start_payload->enc_alg_list, 
493                         &prop->cipher) == FALSE) {
494     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
495     goto err;
496   }
497
498   if (silc_hash_alloc(start_payload->hash_alg_list,
499                       &prop->hash) == FALSE) {
500     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
501     goto err;
502   }
503
504   /* Encode the payload */
505   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
506   if (status != SILC_SKE_STATUS_OK)
507     goto err;
508
509   /* Send the packet. */
510   if (send_packet)
511     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
512
513   silc_buffer_free(payload_buf);
514
515   return status;
516
517  err:
518   if (group)
519     silc_free(group);
520
521   if (prop->pkcs)
522     silc_pkcs_free(prop->pkcs);
523   if (prop->cipher)
524     silc_cipher_free(prop->cipher);
525   if (prop->hash)
526     silc_hash_free(prop->hash);
527   silc_free(prop);
528   ske->prop = NULL;
529
530   if (status == SILC_SKE_STATUS_OK)
531     return SILC_SKE_STATUS_ERROR;
532
533   ske->status = status;
534   return status;
535 }
536
537 /* This function receives the Key Exchange 1 Payload from the initiator.
538    After processing the payload this then selects random number x,
539    such that 1 < x < q and computes f = g ^ x mod p. This then puts
540    the result f to a Key Exchange 2 Payload which is later processed
541    in ske_responder_finish function. The callback function should
542    not touch the payload (it should merely call the ske_responder_finish
543    function). */
544
545 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
546                                          SilcBuffer ke1_payload,
547                                          SilcSKECb callback,
548                                          void *context)
549 {
550   SilcSKEStatus status = SILC_SKE_STATUS_OK;
551   SilcSKEOnePayload *one_payload;
552   SilcSKETwoPayload *two_payload;
553   SilcInt *x, f;
554
555   SILC_LOG_DEBUG(("Start"));
556
557   /* Decode Key Exchange 1 Payload */
558   status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
559   if (status != SILC_SKE_STATUS_OK) {
560     ske->status = status;
561     return status;
562   }
563
564   /* Create the random number x, 1 < x < q. */
565   x = silc_calloc(1, sizeof(*x));
566   silc_mp_init(x);
567   status = 
568     silc_ske_create_rnd(ske, ske->prop->group->group_order,
569                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
570                         x);
571   if (status != SILC_SKE_STATUS_OK) {
572     silc_mp_clear(x);
573     silc_free(x);
574     return status;
575   }
576
577   SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
578
579   /* Do the Diffie Hellman computation, f = g ^ x mod p */
580   silc_mp_init(&f);
581   silc_mp_powm(&f, &ske->prop->group->generator, x, 
582                &ske->prop->group->group);
583   
584   /* Save the results for later processing */
585   two_payload = silc_calloc(1, sizeof(*two_payload));
586   two_payload->f = f;
587   ske->x = x;
588   ske->ke1_payload = one_payload;
589   ske->ke2_payload = two_payload;
590
591   /* Call the callback. */
592   if (callback)
593     (*callback)(ske, context);
594
595   return status;
596 }
597
598 /* This function computes the secret shared key KEY = e ^ x mod p, and, 
599    a hash value to be signed and sent to the other end. This then
600    encodes Key Exchange 2 Payload and sends it to the other end. */
601
602 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
603                                         SilcPublicKey public_key,
604                                         SilcPrivateKey private_key,
605                                         SilcSKEPKType pk_type,
606                                         SilcSKESendPacketCb send_packet,
607                                         void *context)
608 {
609   SilcSKEStatus status = SILC_SKE_STATUS_OK;
610   SilcBuffer payload_buf;
611   SilcInt *KEY;
612   unsigned char hash[32], sign[256], *pk;
613   unsigned int hash_len, sign_len, pk_len;
614
615   SILC_LOG_DEBUG(("Start"));
616
617   if (!public_key || !private_key) {
618     status = SILC_SKE_STATUS_ERROR;
619     goto err;
620   }
621
622   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
623
624   /* Compute the shared secret key */
625   KEY = silc_calloc(1, sizeof(*KEY));
626   silc_mp_init(KEY);
627   silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x, 
628                &ske->prop->group->group);
629   ske->KEY = KEY;
630
631   SILC_LOG_DEBUG(("Getting public key"));
632
633   /* Get the public key */
634   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
635   if (!pk) {
636     status = SILC_SKE_STATUS_ERROR;
637     goto err;
638   }
639   ske->ke2_payload->pk_data = pk;
640   ske->ke2_payload->pk_len = pk_len;
641   ske->ke2_payload->pk_type = pk_type;
642
643   SILC_LOG_DEBUG(("Computing HASH value"));
644
645   /* Compute the hash value */
646   memset(hash, 0, sizeof(hash));
647   status = silc_ske_make_hash(ske, hash, &hash_len);
648   if (status != SILC_SKE_STATUS_OK)
649     goto err;
650
651   ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
652   memcpy(ske->hash, hash, hash_len);
653   ske->hash_len = hash_len;
654
655   SILC_LOG_DEBUG(("Signing HASH value"));
656
657   /* Sign the hash value */
658   silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
659                                  private_key->prv_len);
660   silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
661   ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
662   memcpy(ske->ke2_payload->sign_data, sign, sign_len);
663   memset(sign, 0, sizeof(sign));
664   ske->ke2_payload->sign_len = sign_len;
665
666   /* Encode the Key Exchange 2 Payload */
667   status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
668                                        &payload_buf);
669   if (status != SILC_SKE_STATUS_OK)
670     goto err;
671
672   /* Send the packet. */
673   if (send_packet)
674     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
675
676   silc_buffer_free(payload_buf);
677
678   return status;
679
680  err:
681   silc_mp_clear(ske->KEY);
682   silc_free(ske->KEY);
683   ske->KEY = NULL;
684   silc_ske_payload_two_free(ske->ke2_payload);
685
686   if (status == SILC_SKE_STATUS_OK)
687     return SILC_SKE_STATUS_ERROR;
688
689   ske->status = status;
690   return status;
691 }
692
693 /* The Key Exchange protocol is ended by calling this function. This
694    must not be called until the keys are processed like the protocol
695    defines. This function is for both initiator and responder. */
696
697 SilcSKEStatus silc_ske_end(SilcSKE ske,
698                            SilcSKESendPacketCb send_packet,
699                            void *context)
700 {
701   SilcBuffer packet;
702
703   SILC_LOG_DEBUG(("Start"));
704
705   packet = silc_buffer_alloc(4);
706   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
707   silc_buffer_format(packet,
708                      SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
709                      SILC_STR_END);
710
711   if (send_packet)
712     (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
713
714   silc_buffer_free(packet);
715
716   return SILC_SKE_STATUS_OK;
717 }
718
719 /* Aborts the Key Exchange protocol. This is called if error occurs
720    while performing the protocol. The status argument is the error
721    status and it is sent to the remote end. */
722
723 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
724                              SilcSKESendPacketCb send_packet,
725                              void *context)
726 {
727   SilcBuffer packet;
728
729   SILC_LOG_DEBUG(("Start"));
730
731   packet = silc_buffer_alloc(4);
732   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
733   silc_buffer_format(packet,
734                      SILC_STR_UI_SHORT(status),
735                      SILC_STR_END);
736
737   if (send_packet)
738     (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
739
740   silc_buffer_free(packet);
741
742   return SILC_SKE_STATUS_OK;
743 }
744
745 /* Assembles security properties to Key Exchange Start Payload to be
746    sent to the remote end. This checks system wide (SILC system, that is)
747    settings and chooses from those. However, if other properties
748    should be used this function is easy to replace by another function,
749    as, this function is called by the caller of the protocol and not
750    by the protocol itself. */
751
752 SilcSKEStatus 
753 silc_ske_assemble_security_properties(SilcSKE ske,
754                                       unsigned char flags,
755                                       char *version,
756                                       SilcSKEStartPayload **return_payload)
757 {
758   SilcSKEStartPayload *rp;
759   int i;
760
761   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
762
763   rp = silc_calloc(1, sizeof(*rp));
764
765   /* Set flags */
766   rp->flags = flags;
767
768   /* Set random cookie */
769   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
770   for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
771     rp->cookie[i] = silc_rng_get_byte(ske->rng);
772   rp->cookie_len = SILC_SKE_COOKIE_LEN;
773
774   /* Put version */
775   rp->version = strdup(version);
776   rp->version_len = strlen(version);
777
778   /* Get supported Key Exhange groups */
779   rp->ke_grp_list = silc_ske_get_supported_groups();
780   rp->ke_grp_len = strlen(rp->ke_grp_list);
781
782   /* Get supported PKCS algorithms */
783   rp->pkcs_alg_list = silc_pkcs_get_supported();
784   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
785
786   /* Get supported encryption algorithms */
787   rp->enc_alg_list = silc_cipher_get_supported();
788   rp->enc_alg_len = strlen(rp->enc_alg_list);
789
790   /* Get supported hash algorithms */
791   rp->hash_alg_list = silc_hash_get_supported();
792   rp->hash_alg_len = strlen(rp->hash_alg_list);
793
794   /* XXX */
795   /* Get supported compression algorithms */
796   rp->comp_alg_list = "";
797   rp->comp_alg_len = 0;
798
799   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
800     2 + rp->version_len +
801     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
802     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
803     2 + rp->comp_alg_len;
804
805   *return_payload = rp;
806
807   return SILC_SKE_STATUS_OK;
808 }
809
810 /* Selects the supported security properties from the remote end's Key 
811    Exchange Start Payload. */
812
813 SilcSKEStatus 
814 silc_ske_select_security_properties(SilcSKE ske,
815                                     char *version,
816                                     SilcSKEStartPayload *payload,
817                                     SilcSKEStartPayload *remote_payload)
818 {
819   SilcSKEStatus status;
820   SilcSKEStartPayload *rp;
821   char *cp;
822   int len;
823
824   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
825
826   rp = remote_payload;
827
828   /* Check version string */
829   status = silc_ske_check_version(ske, rp->version, rp->version_len);
830   if (status != SILC_SKE_STATUS_OK) {
831     ske->status = status;
832     return status;
833   }
834
835   /* Flags are returned unchanged. */
836   payload->flags = rp->flags;
837
838   /* Take cookie */
839   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
840   payload->cookie_len = SILC_SKE_COOKIE_LEN;
841   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
842
843   /* Put our version to our reply */
844   payload->version = strdup(version);
845   payload->version_len = strlen(version);
846
847   /* Get supported Key Exchange groups */
848   cp = rp->ke_grp_list;
849   if (cp && strchr(cp, ',')) {
850     while(cp) {
851       char *item;
852
853       len = strcspn(cp, ",");
854       item = silc_calloc(len + 1, sizeof(char));
855       memcpy(item, cp, len);
856
857       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
858
859       if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
860         SILC_LOG_DEBUG(("Found KE group `%s'", item));
861
862         payload->ke_grp_len = len;
863         payload->ke_grp_list = item;
864         break;
865       }
866
867       cp += len;
868       if (strlen(cp) == 0)
869         cp = NULL;
870       else
871         cp++;
872
873       if (item)
874         silc_free(item);
875     }
876
877     if (!payload->ke_grp_len && !payload->ke_grp_list) {
878       SILC_LOG_DEBUG(("Could not find supported KE group"));
879       silc_free(payload);
880       return SILC_SKE_STATUS_UNKNOWN_GROUP;
881     }
882   } else {
883
884     if (!rp->ke_grp_len) {
885       SILC_LOG_DEBUG(("KE group not defined in payload"));
886       silc_free(payload);
887       return SILC_SKE_STATUS_BAD_PAYLOAD;
888     }
889
890     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
891     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
892
893     payload->ke_grp_len = rp->ke_grp_len;
894     payload->ke_grp_list = strdup(rp->ke_grp_list);
895   }
896
897   /* Get supported PKCS algorithms */
898   cp = rp->pkcs_alg_list;
899   if (cp && strchr(cp, ',')) {
900     while(cp) {
901       char *item;
902
903       len = strcspn(cp, ",");
904       item = silc_calloc(len + 1, sizeof(char));
905       memcpy(item, cp, len);
906
907       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
908
909       if (silc_pkcs_is_supported(item) == TRUE) {
910         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
911
912         payload->pkcs_alg_len = len;
913         payload->pkcs_alg_list = item;
914         break;
915       }
916
917       cp += len;
918       if (strlen(cp) == 0)
919         cp = NULL;
920       else
921         cp++;
922
923       if (item)
924         silc_free(item);
925     }
926
927     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
928       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
929       silc_free(payload->ke_grp_list);
930       silc_free(payload);
931       return SILC_SKE_STATUS_UNKNOWN_PKCS;
932     }
933   } else {
934
935     if (!rp->pkcs_alg_len) {
936       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
937       silc_free(payload->ke_grp_list);
938       silc_free(payload);
939       return SILC_SKE_STATUS_BAD_PAYLOAD;
940     }
941
942     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
943     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
944
945     payload->pkcs_alg_len = rp->pkcs_alg_len;
946     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
947   }
948
949   /* Get supported encryption algorithms */
950   cp = rp->enc_alg_list;
951   if (cp && strchr(cp, ',')) {
952     while(cp) {
953       char *item;
954
955       len = strcspn(cp, ",");
956       item = silc_calloc(len + 1, sizeof(char));
957       memcpy(item, cp, len);
958
959       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
960
961       if (silc_cipher_is_supported(item) == TRUE) {
962         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
963
964         payload->enc_alg_len = len;
965         payload->enc_alg_list = item;
966         break;
967       }
968
969       cp += len;
970       if (strlen(cp) == 0)
971         cp = NULL;
972       else
973         cp++;
974
975       if (item)
976         silc_free(item);
977     }
978
979     if (!payload->enc_alg_len && !payload->enc_alg_list) {
980       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
981       silc_free(payload->ke_grp_list);
982       silc_free(payload->pkcs_alg_list);
983       silc_free(payload);
984       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
985     }
986   } else {
987
988     if (!rp->enc_alg_len) {
989       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
990       silc_free(payload->ke_grp_list);
991       silc_free(payload->pkcs_alg_list);
992       silc_free(payload);
993       return SILC_SKE_STATUS_BAD_PAYLOAD;
994     }
995
996     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
997                     rp->enc_alg_list));
998
999     payload->enc_alg_len = rp->enc_alg_len;
1000     payload->enc_alg_list = strdup(rp->enc_alg_list);
1001   }
1002
1003   /* Get supported hash algorithms */
1004   cp = rp->hash_alg_list;
1005   if (cp && strchr(cp, ',')) {
1006     while(cp) {
1007       char *item;
1008
1009       len = strcspn(cp, ",");
1010       item = silc_calloc(len + 1, sizeof(char));
1011       memcpy(item, cp, len);
1012
1013       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1014
1015       if (silc_hash_is_supported(item) == TRUE) {
1016         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1017
1018         payload->hash_alg_len = len;
1019         payload->hash_alg_list = item;
1020         break;
1021       }
1022
1023       cp += len;
1024       if (strlen(cp) == 0)
1025         cp = NULL;
1026       else
1027         cp++;
1028
1029       if (item)
1030         silc_free(item);
1031     }
1032
1033     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1034       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1035       silc_free(payload->ke_grp_list);
1036       silc_free(payload->pkcs_alg_list);
1037       silc_free(payload->enc_alg_list);
1038       silc_free(payload);
1039       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1040     }
1041   } else {
1042
1043     if (!rp->hash_alg_len) {
1044       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1045       silc_free(payload->ke_grp_list);
1046       silc_free(payload->pkcs_alg_list);
1047       silc_free(payload->enc_alg_list);
1048       silc_free(payload);
1049       return SILC_SKE_STATUS_BAD_PAYLOAD;
1050     }
1051
1052     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1053                     rp->hash_alg_list));
1054
1055     payload->hash_alg_len = rp->hash_alg_len;
1056     payload->hash_alg_list = strdup(rp->hash_alg_list);
1057   }
1058
1059 #if 0
1060   /* Get supported compression algorithms */
1061   cp = rp->hash_alg_list;
1062   if (cp && strchr(cp, ',')) {
1063     while(cp) {
1064       char *item;
1065
1066       len = strcspn(cp, ",");
1067       item = silc_calloc(len + 1, sizeof(char));
1068       memcpy(item, cp, len);
1069
1070       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1071
1072       if (silc_hash_is_supported(item) == TRUE) {
1073         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1074
1075         payload->hash_alg_len = len;
1076         payload->hash_alg_list = item;
1077         break;
1078       }
1079
1080       cp += len;
1081       if (strlen(cp) == 0)
1082         cp = NULL;
1083       else
1084         cp++;
1085
1086       if (item)
1087         silc_free(item);
1088     }
1089
1090     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1091       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1092       silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1093       silc_free(payload->ke_grp_list);
1094       silc_free(payload->pkcs_alg_list);
1095       silc_free(payload->enc_alg_list);
1096       silc_free(payload);
1097       return;
1098     }
1099   } else {
1100
1101   }
1102 #endif
1103
1104   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1105     2 + payload->version_len + 
1106     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1107     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1108     2 + payload->comp_alg_len;
1109
1110   return SILC_SKE_STATUS_OK;
1111 }
1112
1113 /* Creates random number such that 1 < rnd < n and at most length
1114    of len bits. The rnd sent as argument must be initialized. */
1115
1116 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
1117                                   unsigned int len, 
1118                                   SilcInt *rnd)
1119 {
1120   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1121   unsigned char *string;
1122
1123   SILC_LOG_DEBUG(("Creating random number"));
1124
1125   /* Get the random number as string */
1126   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1127   if (!string)
1128     return SILC_SKE_STATUS_ERROR;
1129
1130   /* Decode the string into a MP integer */
1131   silc_mp_bin2mp(string, (len / 8), rnd);
1132   silc_mp_mod_2exp(rnd, rnd, len);
1133
1134   /* Checks */
1135   if (silc_mp_cmp_ui(rnd, 1) < 0)
1136     status = SILC_SKE_STATUS_ERROR;
1137
1138   if (silc_mp_cmp(rnd, &n) >= 0)
1139     status = SILC_SKE_STATUS_ERROR;
1140
1141   memset(string, 'F', (len / 8));
1142   silc_free(string);
1143
1144   return status;
1145 }
1146
1147 /* Creates a hash value HASH as defined in the SKE protocol. */
1148
1149 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1150                                  unsigned char *return_hash,
1151                                  unsigned int *return_hash_len)
1152 {
1153   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1154   SilcBuffer buf;
1155   unsigned char *e, *f, *KEY;
1156   unsigned int e_len, f_len, KEY_len;
1157   int ret;
1158
1159   SILC_LOG_DEBUG(("Start"));
1160
1161   e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len);
1162   f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len);
1163   KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1164
1165   buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1166                           ske->pk_len + e_len + f_len + KEY_len);
1167   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1168
1169   /* Format the buffer used to compute the hash value */
1170   ret = silc_buffer_format(buf,
1171                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1172                                                 ske->start_payload_copy->len),
1173                            SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1174                            SILC_STR_UI_XNSTRING(e, e_len),
1175                            SILC_STR_UI_XNSTRING(f, f_len),
1176                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
1177                            SILC_STR_END);
1178   if (ret == -1) {
1179     silc_buffer_free(buf);
1180     memset(e, 0, e_len);
1181     memset(f, 0, f_len);
1182     memset(KEY, 0, KEY_len);
1183     silc_free(e);
1184     silc_free(f);
1185     silc_free(KEY);
1186     return SILC_SKE_STATUS_ERROR;
1187   }
1188
1189   /* Make the hash */
1190   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1191   *return_hash_len = ske->prop->hash->hash->hash_len;
1192
1193   SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1194
1195   silc_buffer_free(buf);
1196   memset(e, 0, e_len);
1197   memset(f, 0, f_len);
1198   memset(KEY, 0, KEY_len);
1199   silc_free(e);
1200   silc_free(f);
1201   silc_free(KEY);
1202
1203   return status;
1204 }
1205
1206 /* Processes the provided key material `data' as the SILC protocol 
1207    specification specifies. */
1208
1209 SilcSKEStatus 
1210 silc_ske_process_key_material_data(unsigned char *data,
1211                                    unsigned int data_len,
1212                                    unsigned int req_iv_len,
1213                                    unsigned int req_enc_key_len,
1214                                    unsigned int req_hmac_key_len,
1215                                    SilcHash hash,
1216                                    SilcSKEKeyMaterial *key)
1217 {
1218   SilcBuffer buf;
1219   unsigned char hashd[32];
1220   unsigned int hash_len = req_hmac_key_len;
1221   unsigned int enc_key_len = req_enc_key_len / 8;
1222
1223   SILC_LOG_DEBUG(("Start"));
1224
1225   buf = silc_buffer_alloc(1 + data_len);
1226   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1227   silc_buffer_format(buf,
1228                      SILC_STR_UI_CHAR(0),
1229                      SILC_STR_UI_XNSTRING(data, data_len),
1230                      SILC_STR_END);
1231
1232   /* Take IVs */
1233   memset(hashd, 0, sizeof(hashd));
1234   buf->data[0] = 0;
1235   silc_hash_make(hash, buf->data, buf->len, hashd);
1236   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1237   memcpy(key->send_iv, hashd, req_iv_len);
1238   memset(hashd, 0, sizeof(hashd));
1239   buf->data[0] = 1;
1240   silc_hash_make(hash, buf->data, buf->len, hashd);
1241   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1242   memcpy(key->receive_iv, hashd, req_iv_len);
1243   key->iv_len = req_iv_len;
1244
1245   /* Take the encryption keys. If requested key size is more than
1246      the size of hash length we will distribute more key material
1247      as protocol defines. */
1248   buf->data[0] = 2;
1249   if (enc_key_len > hash_len) {
1250     SilcBuffer dist;
1251     unsigned char k1[32], k2[32], k3[32];
1252     unsigned char *dtmp;
1253     
1254     /* XXX */
1255     if (enc_key_len > (3 * hash_len))
1256       return SILC_SKE_STATUS_ERROR;
1257     
1258     /* Take first round */
1259     memset(k1, 0, sizeof(k1));
1260     silc_hash_make(hash, buf->data, buf->len, k1);
1261     
1262     /* Take second round */
1263     dist = silc_buffer_alloc(data_len + hash_len);
1264     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1265     silc_buffer_format(dist,
1266                        SILC_STR_UI_XNSTRING(data, data_len),
1267                        SILC_STR_UI_XNSTRING(k1, hash_len),
1268                        SILC_STR_END);
1269     memset(k2, 0, sizeof(k2));
1270     silc_hash_make(hash, dist->data, dist->len, k2);
1271     
1272     /* Take third round */
1273     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1274     silc_buffer_pull(dist, data_len + hash_len);
1275     silc_buffer_format(dist,
1276                        SILC_STR_UI_XNSTRING(k2, hash_len),
1277                        SILC_STR_END);
1278     silc_buffer_push(dist, data_len + hash_len);
1279     memset(k3, 0, sizeof(k3));
1280     silc_hash_make(hash, dist->data, dist->len, k3);
1281
1282     /* Then, save the keys */
1283     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1284     memcpy(dtmp, k1, hash_len);
1285     memcpy(dtmp + hash_len, k2, hash_len);
1286     memcpy(dtmp + hash_len, k3, hash_len);
1287
1288     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1289     memcpy(key->send_enc_key, dtmp, enc_key_len);
1290     key->enc_key_len = req_enc_key_len;
1291
1292     memset(dtmp, 0, (3 * hash_len));
1293     memset(k1, 0, sizeof(k1));
1294     memset(k2, 0, sizeof(k2));
1295     memset(k3, 0, sizeof(k3));
1296     silc_free(dtmp);
1297     silc_buffer_free(dist);
1298   } else {
1299     /* Take normal hash as key */
1300     memset(hashd, 0, sizeof(hashd));
1301     silc_hash_make(hash, buf->data, buf->len, hashd);
1302     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1303     memcpy(key->send_enc_key, hashd, enc_key_len);
1304     key->enc_key_len = req_enc_key_len;
1305   }
1306
1307   buf->data[0] = 3;
1308   if (enc_key_len > hash_len) {
1309     SilcBuffer dist;
1310     unsigned char k1[32], k2[32], k3[32];
1311     unsigned char *dtmp;
1312     
1313     /* XXX */
1314     if (enc_key_len > (3 * hash_len))
1315       return SILC_SKE_STATUS_ERROR;
1316     
1317     /* Take first round */
1318     memset(k1, 0, sizeof(k1));
1319     silc_hash_make(hash, buf->data, buf->len, k1);
1320     
1321     /* Take second round */
1322     dist = silc_buffer_alloc(data_len + hash_len);
1323     silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1324     silc_buffer_format(dist,
1325                        SILC_STR_UI_XNSTRING(data, data_len),
1326                        SILC_STR_UI_XNSTRING(k1, hash_len),
1327                        SILC_STR_END);
1328     memset(k2, 0, sizeof(k2));
1329     silc_hash_make(hash, dist->data, dist->len, k2);
1330     
1331     /* Take third round */
1332     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1333     silc_buffer_pull(dist, data_len + hash_len);
1334     silc_buffer_format(dist,
1335                        SILC_STR_UI_XNSTRING(k2, hash_len),
1336                        SILC_STR_END);
1337     silc_buffer_push(dist, data_len + hash_len);
1338     memset(k3, 0, sizeof(k3));
1339     silc_hash_make(hash, dist->data, dist->len, k3);
1340
1341     /* Then, save the keys */
1342     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1343     memcpy(dtmp, k1, hash_len);
1344     memcpy(dtmp + hash_len, k2, hash_len);
1345     memcpy(dtmp + hash_len, k3, hash_len);
1346
1347     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1348     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1349     key->enc_key_len = req_enc_key_len;
1350
1351     memset(dtmp, 0, (3 * hash_len));
1352     memset(k1, 0, sizeof(k1));
1353     memset(k2, 0, sizeof(k2));
1354     memset(k3, 0, sizeof(k3));
1355     silc_free(dtmp);
1356     silc_buffer_free(dist);
1357   } else {
1358     /* Take normal hash as key */
1359     memset(hashd, 0, sizeof(hashd));
1360     silc_hash_make(hash, buf->data, buf->len, hashd);
1361     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1362     memcpy(key->receive_enc_key, hashd, enc_key_len);
1363     key->enc_key_len = req_enc_key_len;
1364   }
1365
1366   /* Take HMAC key */
1367   memset(hashd, 0, sizeof(hashd));
1368   buf->data[0] = 4;
1369   silc_hash_make(hash, buf->data, buf->len, hashd);
1370   key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1371   memcpy(key->hmac_key, hashd, req_hmac_key_len);
1372   key->hmac_key_len = req_hmac_key_len;
1373
1374   silc_buffer_free(buf);
1375
1376   return SILC_SKE_STATUS_OK;
1377 }
1378
1379 /* Processes negotiated key material as protocol specifies. This returns
1380    the actual keys to be used in the SILC. */
1381
1382 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1383                                             unsigned int req_iv_len,
1384                                             unsigned int req_enc_key_len,
1385                                             unsigned int req_hmac_key_len,
1386                                             SilcSKEKeyMaterial *key)
1387 {
1388   SilcSKEStatus status;
1389   SilcBuffer buf;
1390   unsigned char *tmpbuf;
1391   int klen;
1392
1393   /* Encode KEY to binary data */
1394   tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1395
1396   buf = silc_buffer_alloc(klen + ske->hash_len);
1397   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1398   silc_buffer_format(buf,
1399                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
1400                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1401                      SILC_STR_END);
1402
1403   /* Process the key material */
1404   status = silc_ske_process_key_material_data(buf->data, buf->len,
1405                                               req_iv_len, req_enc_key_len,
1406                                               req_hmac_key_len, 
1407                                               ske->prop->hash, key);
1408
1409   memset(tmpbuf, 0, klen);
1410   silc_free(tmpbuf);
1411   silc_buffer_free(buf);
1412
1413   return status;
1414 }
1415
1416 /* Free key material structure */
1417
1418 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1419 {
1420   if (key->send_iv)
1421     silc_free(key->send_iv);
1422   if (key->receive_iv)
1423     silc_free(key->receive_iv);
1424   if (key->send_enc_key) {
1425     memset(key->send_enc_key, 0, key->enc_key_len);
1426     silc_free(key->send_enc_key);
1427   }
1428   if (key->receive_enc_key) {
1429     memset(key->receive_enc_key, 0, key->enc_key_len);
1430     silc_free(key->receive_enc_key);
1431   }
1432   if (key->hmac_key) {
1433     memset(key->hmac_key, 0, key->hmac_key_len);
1434     silc_free(key->hmac_key);
1435   }
1436 }