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