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