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