Moved silc_client_ch[u]mode[_char] to client library from silc/.
[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   SilcSKEStartPayload *rp;
779   char *cp;
780   int len;
781
782   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
783
784   rp = remote_payload;
785
786   /* Flags are returned unchanged. */
787   payload->flags = rp->flags;
788
789   /* Take cookie */
790   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
791   payload->cookie_len = SILC_SKE_COOKIE_LEN;
792   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
793
794   /* Check version string */
795   silc_ske_check_version(ske, rp->version, rp->version_len);
796
797   /* Put our version to our reply */
798   payload->version = strdup(version);
799   payload->version_len = strlen(version);
800
801   /* Get supported Key Exchange groups */
802   cp = rp->ke_grp_list;
803   if (cp && strchr(cp, ',')) {
804     while(cp) {
805       char *item;
806
807       len = strcspn(cp, ",");
808       item = silc_calloc(len + 1, sizeof(char));
809       memcpy(item, cp, len);
810
811       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
812
813       if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
814         SILC_LOG_DEBUG(("Found KE group `%s'", item));
815
816         payload->ke_grp_len = len;
817         payload->ke_grp_list = item;
818         break;
819       }
820
821       cp += len;
822       if (strlen(cp) == 0)
823         cp = NULL;
824       else
825         cp++;
826
827       if (item)
828         silc_free(item);
829     }
830
831     if (!payload->ke_grp_len && !payload->ke_grp_list) {
832       SILC_LOG_DEBUG(("Could not find supported KE group"));
833       silc_free(payload);
834       return SILC_SKE_STATUS_UNKNOWN_GROUP;
835     }
836   } else {
837
838     if (!rp->ke_grp_len) {
839       SILC_LOG_DEBUG(("KE group not defined in payload"));
840       silc_free(payload);
841       return SILC_SKE_STATUS_BAD_PAYLOAD;
842     }
843
844     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
845     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
846
847     payload->ke_grp_len = rp->ke_grp_len;
848     payload->ke_grp_list = strdup(rp->ke_grp_list);
849   }
850
851   /* Get supported PKCS algorithms */
852   cp = rp->pkcs_alg_list;
853   if (cp && strchr(cp, ',')) {
854     while(cp) {
855       char *item;
856
857       len = strcspn(cp, ",");
858       item = silc_calloc(len + 1, sizeof(char));
859       memcpy(item, cp, len);
860
861       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
862
863       if (silc_pkcs_is_supported(item) == TRUE) {
864         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
865
866         payload->pkcs_alg_len = len;
867         payload->pkcs_alg_list = item;
868         break;
869       }
870
871       cp += len;
872       if (strlen(cp) == 0)
873         cp = NULL;
874       else
875         cp++;
876
877       if (item)
878         silc_free(item);
879     }
880
881     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
882       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
883       silc_free(payload->ke_grp_list);
884       silc_free(payload);
885       return SILC_SKE_STATUS_UNKNOWN_PKCS;
886     }
887   } else {
888
889     if (!rp->pkcs_alg_len) {
890       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
891       silc_free(payload->ke_grp_list);
892       silc_free(payload);
893       return SILC_SKE_STATUS_BAD_PAYLOAD;
894     }
895
896     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
897     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
898
899     payload->pkcs_alg_len = rp->pkcs_alg_len;
900     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
901   }
902
903   /* Get supported encryption algorithms */
904   cp = rp->enc_alg_list;
905   if (cp && strchr(cp, ',')) {
906     while(cp) {
907       char *item;
908
909       len = strcspn(cp, ",");
910       item = silc_calloc(len + 1, sizeof(char));
911       memcpy(item, cp, len);
912
913       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
914
915       if (silc_cipher_is_supported(item) == TRUE) {
916         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
917
918         payload->enc_alg_len = len;
919         payload->enc_alg_list = item;
920         break;
921       }
922
923       cp += len;
924       if (strlen(cp) == 0)
925         cp = NULL;
926       else
927         cp++;
928
929       if (item)
930         silc_free(item);
931     }
932
933     if (!payload->enc_alg_len && !payload->enc_alg_list) {
934       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
935       silc_free(payload->ke_grp_list);
936       silc_free(payload->pkcs_alg_list);
937       silc_free(payload);
938       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
939     }
940   } else {
941
942     if (!rp->enc_alg_len) {
943       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
944       silc_free(payload->ke_grp_list);
945       silc_free(payload->pkcs_alg_list);
946       silc_free(payload);
947       return SILC_SKE_STATUS_BAD_PAYLOAD;
948     }
949
950     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
951                     rp->enc_alg_list));
952
953     payload->enc_alg_len = rp->enc_alg_len;
954     payload->enc_alg_list = strdup(rp->enc_alg_list);
955   }
956
957   /* Get supported hash algorithms */
958   cp = rp->hash_alg_list;
959   if (cp && strchr(cp, ',')) {
960     while(cp) {
961       char *item;
962
963       len = strcspn(cp, ",");
964       item = silc_calloc(len + 1, sizeof(char));
965       memcpy(item, cp, len);
966
967       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
968
969       if (silc_hash_is_supported(item) == TRUE) {
970         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
971
972         payload->hash_alg_len = len;
973         payload->hash_alg_list = item;
974         break;
975       }
976
977       cp += len;
978       if (strlen(cp) == 0)
979         cp = NULL;
980       else
981         cp++;
982
983       if (item)
984         silc_free(item);
985     }
986
987     if (!payload->hash_alg_len && !payload->hash_alg_list) {
988       SILC_LOG_DEBUG(("Could not find supported hash alg"));
989       silc_free(payload->ke_grp_list);
990       silc_free(payload->pkcs_alg_list);
991       silc_free(payload->enc_alg_list);
992       silc_free(payload);
993       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
994     }
995   } else {
996
997     if (!rp->hash_alg_len) {
998       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
999       silc_free(payload->ke_grp_list);
1000       silc_free(payload->pkcs_alg_list);
1001       silc_free(payload->enc_alg_list);
1002       silc_free(payload);
1003       return SILC_SKE_STATUS_BAD_PAYLOAD;
1004     }
1005
1006     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1007                     rp->hash_alg_list));
1008
1009     payload->hash_alg_len = rp->hash_alg_len;
1010     payload->hash_alg_list = strdup(rp->hash_alg_list);
1011   }
1012
1013 #if 0
1014   /* Get supported compression algorithms */
1015   cp = rp->hash_alg_list;
1016   if (cp && strchr(cp, ',')) {
1017     while(cp) {
1018       char *item;
1019
1020       len = strcspn(cp, ",");
1021       item = silc_calloc(len + 1, sizeof(char));
1022       memcpy(item, cp, len);
1023
1024       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1025
1026       if (silc_hash_is_supported(item) == TRUE) {
1027         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1028
1029         payload->hash_alg_len = len;
1030         payload->hash_alg_list = item;
1031         break;
1032       }
1033
1034       cp += len;
1035       if (strlen(cp) == 0)
1036         cp = NULL;
1037       else
1038         cp++;
1039
1040       if (item)
1041         silc_free(item);
1042     }
1043
1044     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1045       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1046       silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1047       silc_free(payload->ke_grp_list);
1048       silc_free(payload->pkcs_alg_list);
1049       silc_free(payload->enc_alg_list);
1050       silc_free(payload);
1051       return;
1052     }
1053   } else {
1054
1055   }
1056 #endif
1057
1058   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1059     2 + payload->version_len + 
1060     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1061     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1062     2 + payload->comp_alg_len;
1063
1064   return SILC_SKE_STATUS_OK;
1065 }
1066
1067 /* Creates random number such that 1 < rnd < n and at most length
1068    of len bits. The rnd sent as argument must be initialized. */
1069
1070 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
1071                                   unsigned int len, 
1072                                   SilcInt *rnd)
1073 {
1074   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1075   unsigned char *string;
1076
1077   SILC_LOG_DEBUG(("Creating random number"));
1078
1079   /* Get the random number as string */
1080   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1081
1082   /* Decode the string into a MP integer */
1083   silc_mp_bin2mp(string, (len / 8), rnd);
1084   silc_mp_mod_2exp(rnd, rnd, len);
1085
1086   /* Checks */
1087   if (silc_mp_cmp_ui(rnd, 1) < 0)
1088     status = SILC_SKE_STATUS_ERROR;
1089
1090   if (silc_mp_cmp(rnd, &n) >= 0)
1091     status = SILC_SKE_STATUS_ERROR;
1092
1093   memset(string, 'F', (len / 8));
1094   silc_free(string);
1095
1096   return status;
1097 }
1098
1099 /* Creates a hash value HASH as defined in the SKE protocol. */
1100
1101 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1102                                  unsigned char *return_hash,
1103                                  unsigned int *return_hash_len)
1104 {
1105   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1106   SilcBuffer buf;
1107   unsigned char *e, *f, *KEY;
1108   unsigned int e_len, f_len, KEY_len;
1109
1110   SILC_LOG_DEBUG(("Start"));
1111
1112   e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1113   f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1114   KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
1115
1116   buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1117                           ske->pk_len + e_len + f_len + KEY_len);
1118   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1119
1120   /* Format the buffer used to compute the hash value */
1121   silc_buffer_format(buf,
1122                      SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1123                                           ske->start_payload_copy->len),
1124                      SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1125                      SILC_STR_UI_XNSTRING(e, e_len),
1126                      SILC_STR_UI_XNSTRING(f, f_len),
1127                      SILC_STR_UI_XNSTRING(KEY, KEY_len),
1128                      SILC_STR_END);
1129
1130 #if 0
1131   SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1132 #endif
1133
1134   /* Make the hash */
1135   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1136   *return_hash_len = ske->prop->hash->hash->hash_len;
1137
1138   SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1139
1140   silc_buffer_free(buf);
1141   memset(e, 0, e_len);
1142   memset(f, 0, f_len);
1143   memset(KEY, 0, KEY_len);
1144   silc_free(e);
1145   silc_free(f);
1146   silc_free(KEY);
1147
1148   return status;
1149 }
1150
1151 /* Processes negotiated key material as protocol specifies. This returns
1152    the actual keys to be used in the SILC. */
1153
1154 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1155                                             unsigned int req_iv_len,
1156                                             unsigned int req_enc_key_len,
1157                                             unsigned int req_hmac_key_len,
1158                                             SilcSKEKeyMaterial *key)
1159 {
1160   int klen;
1161   SilcBuffer buf;
1162   unsigned char *tmpbuf;
1163   unsigned char hash[32];
1164   unsigned int hash_len = ske->prop->hash->hash->hash_len;
1165   unsigned int enc_key_len = req_enc_key_len / 8;
1166
1167   SILC_LOG_DEBUG(("Start"));
1168
1169   /* Encode KEY to binary data */
1170   tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
1171
1172   buf = silc_buffer_alloc(1 + klen + hash_len);
1173   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1174   silc_buffer_format(buf,
1175                      SILC_STR_UI_CHAR(0),
1176                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
1177                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1178                      SILC_STR_END);
1179
1180   /* Take IVs */
1181   memset(hash, 0, sizeof(hash));
1182   buf->data[0] = 0;
1183   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1184   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1185   memcpy(key->send_iv, hash, req_iv_len);
1186   memset(hash, 0, sizeof(hash));
1187   buf->data[0] = 1;
1188   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1189   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1190   memcpy(key->receive_iv, hash, req_iv_len);
1191   key->iv_len = req_iv_len;
1192
1193   /* Take the encryption keys. If requested key size is more than
1194      the size of hash length we will distribute more key material
1195      as protocol defines. */
1196   buf->data[0] = 2;
1197   if (enc_key_len > hash_len) {
1198     SilcBuffer dist;
1199     unsigned char k1[32], k2[32], k3[32];
1200     unsigned char *dtmp;
1201     
1202     /* XXX */
1203     if (enc_key_len > (3 * hash_len))
1204       return SILC_SKE_STATUS_ERROR;
1205     
1206     memset(k1, 0, sizeof(k1));
1207     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1208     
1209     /* XXX */
1210     dist = silc_buffer_alloc(hash_len * 3);
1211     
1212     silc_buffer_pull_tail(dist, klen + hash_len);
1213     silc_buffer_format(dist,
1214                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1215                        SILC_STR_UI_XNSTRING(k1, hash_len),
1216                        SILC_STR_END);
1217     
1218     memset(k2, 0, sizeof(k2));
1219     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1220     
1221     silc_buffer_pull(dist, klen + hash_len);
1222     silc_buffer_format(dist,
1223                        SILC_STR_UI_XNSTRING(k2, hash_len),
1224                        SILC_STR_END);
1225     silc_buffer_push(dist, klen + hash_len);
1226     
1227     memset(k3, 0, sizeof(k3));
1228     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1229     
1230     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1231     memcpy(dtmp, k1, hash_len);
1232     memcpy(dtmp + hash_len, k2, hash_len);
1233     memcpy(dtmp + hash_len, k3, hash_len);
1234
1235     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1236     memcpy(key->send_enc_key, dtmp, enc_key_len);
1237     key->enc_key_len = req_enc_key_len;
1238
1239     memset(dtmp, 0, (3 * hash_len));
1240     memset(k1, 0, sizeof(k1));
1241     memset(k2, 0, sizeof(k2));
1242     memset(k3, 0, sizeof(k3));
1243     silc_free(dtmp);
1244     silc_buffer_free(dist);
1245   } else {
1246     /* Take normal hash as key */
1247     memset(hash, 0, sizeof(hash));
1248     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1249     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1250     memcpy(key->send_enc_key, hash, enc_key_len);
1251     key->enc_key_len = req_enc_key_len;
1252   }
1253
1254   buf->data[0] = 3;
1255   if (enc_key_len > hash_len) {
1256     SilcBuffer dist;
1257     unsigned char k1[32], k2[32], k3[32];
1258     unsigned char *dtmp;
1259     
1260     /* XXX */
1261     if (enc_key_len > (3 * hash_len))
1262       return SILC_SKE_STATUS_ERROR;
1263     
1264     memset(k1, 0, sizeof(k1));
1265     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1266     
1267     /* XXX */
1268     dist = silc_buffer_alloc(hash_len * 3);
1269     
1270     silc_buffer_pull_tail(dist, klen + hash_len);
1271     silc_buffer_format(dist,
1272                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1273                        SILC_STR_UI_XNSTRING(k1, hash_len),
1274                        SILC_STR_END);
1275     
1276     memset(k2, 0, sizeof(k2));
1277     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1278     
1279     silc_buffer_pull(dist, klen + hash_len);
1280     silc_buffer_format(dist,
1281                        SILC_STR_UI_XNSTRING(k2, hash_len),
1282                        SILC_STR_END);
1283     silc_buffer_push(dist, klen + hash_len);
1284     
1285     memset(k3, 0, sizeof(k3));
1286     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1287     
1288     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1289     memcpy(dtmp, k1, hash_len);
1290     memcpy(dtmp + hash_len, k2, hash_len);
1291     memcpy(dtmp + hash_len, k3, hash_len);
1292
1293     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1294     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1295     key->enc_key_len = req_enc_key_len;
1296
1297     memset(dtmp, 0, (3 * hash_len));
1298     memset(k1, 0, sizeof(k1));
1299     memset(k2, 0, sizeof(k2));
1300     memset(k3, 0, sizeof(k3));
1301     silc_free(dtmp);
1302     silc_buffer_free(dist);
1303   } else {
1304     /* Take normal hash as key */
1305     memset(hash, 0, sizeof(hash));
1306     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1307     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1308     memcpy(key->receive_enc_key, hash, enc_key_len);
1309     key->enc_key_len = req_enc_key_len;
1310   }
1311
1312   /* Take HMAC key */
1313   memset(hash, 0, sizeof(hash));
1314   buf->data[0] = 4;
1315   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1316   key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1317   memcpy(key->hmac_key, hash, req_hmac_key_len);
1318   key->hmac_key_len = req_hmac_key_len;
1319
1320   memset(tmpbuf, 0, klen);
1321   silc_free(tmpbuf);
1322
1323   return SILC_SKE_STATUS_OK;
1324 }