Added mp binary encoding as protocols defines.
[silc.git] / lib / silcske / silcske.c
1 /*
2
3   silcske.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * $Id$
22  * $Log$
23  * Revision 1.5  2000/07/10 05:34:22  priikone
24  *      Added mp binary encoding as protocols defines.
25  *
26  * Revision 1.4  2000/07/07 06:46:43  priikone
27  *      Removed ske_verify_public_key function as it is not needed
28  *      anymore. Added support to the public key verification as callback
29  *      function. Other minor changes and bug fixes.
30  *
31  * Revision 1.3  2000/07/06 07:12:39  priikone
32  *      Support for SILC style public keys added.
33  *
34  * Revision 1.2  2000/07/05 06:05:15  priikone
35  *      Global cosmetic change.
36  *
37  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
38  *      Imported from internal CVS/Added Log headers.
39  *
40  *
41  */
42
43 #include "silcincludes.h"
44 #include "payload_internal.h"
45 #include "groups_internal.h"
46
47 /* Allocates new SKE object. */
48
49 SilcSKE silc_ske_alloc()
50 {
51   SilcSKE ske;
52
53   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
54
55   ske = silc_calloc(1, sizeof(*ske));
56
57   return ske;
58 }
59
60 /* Free's SKE object. */
61
62 void silc_ske_free(SilcSKE ske)
63 {
64   SILC_LOG_DEBUG(("Freeing Key Exchange object"));
65
66   if (ske) {
67     /* Free start payload */
68     if (ske->start_payload)
69       silc_ske_payload_start_free(ske->start_payload);
70
71     /* Free KE1 payload */
72     if (ske->ke1_payload)
73       silc_ske_payload_one_free(ske->ke1_payload);
74
75     /* Free KE2 payload */
76     if (ske->ke2_payload)
77       silc_ske_payload_two_free(ske->ke2_payload);
78
79     /* Free rest */
80     if (ske->prop) {
81       if (ske->prop->group)
82         silc_free(ske->prop->group);
83       if (ske->prop->pkcs)
84         silc_pkcs_free(ske->prop->pkcs);
85       if (ske->prop->cipher)
86         silc_cipher_free(ske->prop->cipher);
87       if (ske->prop->hash)
88         silc_hash_free(ske->prop->hash);
89       silc_free(ske->prop);
90     }
91     if (ske->start_payload_copy)
92       silc_buffer_free(ske->start_payload_copy);
93     if (ske->pk)
94       silc_free(ske->pk);
95     /* XXX
96     silc_mp_clear(&ske->x);
97     silc_mp_clear(&ske->KEY);
98     */
99     if (ske->hash)
100       silc_free(ske->hash);
101     silc_free(ske);
102   }
103 }
104
105 /* Starts the SILC Key Exchange protocol for initiator. The connection
106    to the remote end must be established before calling this function
107    and the connecting socket must be sent as argument. This function
108    creates the Key Exchange Start Paload which includes all our
109    configured security properties. This payload is then sent to the
110    remote end for further processing. This payload must be sent as
111    argument to the function, however, it must not be encoded
112    already, it is done by this function.
113
114    The packet sending is done by calling a callback function. Caller
115    must provide a routine to send the packet. */
116
117 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
118                                        SilcSocketConnection sock,
119                                        SilcSKEStartPayload *start_payload,
120                                        SilcSKESendPacketCb send_packet,
121                                        void *context)
122 {
123   SilcSKEStatus status = SILC_SKE_STATUS_OK;
124   SilcBuffer payload_buf;
125
126   SILC_LOG_DEBUG(("Start"));
127
128   ske->sock = sock;
129   ske->rng = rng;
130
131   /* Encode the payload */
132   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
133   if (status != SILC_SKE_STATUS_OK)
134     return status;
135
136   /* Take a copy of the payload buffer for future use. It is used to
137      compute the HASH value. */
138   ske->start_payload_copy = silc_buffer_copy(payload_buf);
139
140   /* Send the packet. */
141   if (send_packet)
142     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
143
144   silc_buffer_free(payload_buf);
145
146   return status;
147 }
148
149 /* Function called after ske_initiator_start fuction. This receives
150    the remote ends Key Exchange Start payload which includes the
151    security properties selected by the responder from our payload
152    sent in the silc_ske_initiator_start function. */
153
154 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
155                                          SilcBuffer start_payload,
156                                          SilcSKECb callback,
157                                          void *context)
158 {
159   SilcSKEStatus status = SILC_SKE_STATUS_OK;
160   SilcSKEStartPayload *payload;
161   SilcSKESecurityProperties prop;
162   SilcSKEDiffieHellmanGroup group;
163
164   SILC_LOG_DEBUG(("Start"));
165
166   /* Decode the payload */
167   status = silc_ske_payload_start_decode(ske, start_payload, &payload);
168   if (status != SILC_SKE_STATUS_OK)
169     return status;
170
171   /* Take the selected security properties into use while doing
172      the key exchange. This is used only while doing the key 
173      exchange. The same data is returned to upper levels by calling
174      the callback function. */
175   ske->prop = prop = silc_calloc(1, sizeof(*prop));
176   prop->flags = payload->flags;
177   status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
178   if (status != SILC_SKE_STATUS_OK)
179     goto err;
180
181   prop->group = group;
182
183   if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
184     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
185     goto err;
186   }
187
188   if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
189     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
190     goto err;
191   }
192
193   if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
194     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
195     goto err;
196   }
197
198   ske->start_payload = payload;
199
200   /* Return the received payload by calling the callback function. */
201   if (callback)
202     (*callback)(ske, context);
203
204   return status;
205
206  err:
207   if (payload)
208     silc_ske_payload_start_free(payload);
209
210   silc_free(group);
211
212   if (prop->pkcs)
213     silc_pkcs_free(prop->pkcs);
214   if (prop->cipher)
215     silc_cipher_free(prop->cipher);
216   if (prop->hash)
217     silc_hash_free(prop->hash);
218   silc_free(prop);
219   ske->prop = NULL;
220
221   if (status == SILC_SKE_STATUS_OK)
222     return SILC_SKE_STATUS_ERROR;
223
224   return status;
225 }
226
227 /* This function creates random number x, such that 1 < x < q and 
228    computes e = g ^ x mod p and sends the result to the remote end in 
229    Key Exchange 1 Payload. */
230
231 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
232                                          SilcSKESendPacketCb send_packet,
233                                          void *context)
234 {
235   SilcSKEStatus status = SILC_SKE_STATUS_OK;
236   SilcBuffer payload_buf;
237   SilcInt x, e;
238   SilcSKEOnePayload *payload;
239
240   SILC_LOG_DEBUG(("Start"));
241
242   /* Create the random number x, 1 < x < q. */
243   silc_mp_init(&x);
244   status = 
245     silc_ske_create_rnd(ske, ske->prop->group->group_order,
246                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
247                         &x);
248   if (status != SILC_SKE_STATUS_OK) {
249     silc_mp_clear(&x);
250     return status;
251   }
252
253   SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
254
255   /* Do the Diffie Hellman computation, e = g ^ x mod p */
256   silc_mp_init(&e);
257   silc_mp_powm(&e, &ske->prop->group->generator, &x, 
258                &ske->prop->group->group);
259   
260   /* Encode the result to Key Exchange 1 Payload. */
261   payload = silc_calloc(1, sizeof(*payload));
262   payload->e = e;
263   status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
264   if (status != SILC_SKE_STATUS_OK) {
265     silc_mp_clear(&x);
266     silc_mp_clear(&e);
267     silc_free(payload);
268     return status;
269   }
270
271   ske->ke1_payload = payload;
272   ske->x = x;
273
274   /* Send the packet. */
275   if (send_packet)
276     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
277
278   silc_buffer_free(payload_buf);
279
280   return status;
281 }
282
283 /* Receives Key Exchange 2 Payload from responder consisting responders
284    public key, f, and signature. This function verifies the public key,
285    computes the secret shared key and verifies the signature. */
286
287 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
288                                         SilcBuffer ke2_payload,
289                                         SilcSKEVerifyCb verify_key,
290                                         void *verify_context,
291                                         SilcSKECb callback,
292                                         void *context)
293 {
294   SilcSKEStatus status = SILC_SKE_STATUS_OK;
295   SilcSKETwoPayload *payload;
296   SilcPublicKey public_key = NULL;
297   SilcInt KEY;
298   unsigned char hash[32];
299   unsigned int hash_len;
300
301   SILC_LOG_DEBUG(("Start"));
302
303   /* Decode the payload */
304   status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
305   if (status != SILC_SKE_STATUS_OK)
306     return status;
307   ske->ke2_payload = payload;
308
309   SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
310
311   /* Compute the shared secret key */
312   silc_mp_init(&KEY);
313   silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
314   ske->KEY = KEY;
315
316   SILC_LOG_DEBUG(("Verifying public key"));
317
318   if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, 
319                                    &public_key)) {
320     status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
321     goto err;
322   }
323
324   if (verify_key) {
325     status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
326                            payload->pk_type, verify_context);
327     if (status != SILC_SKE_STATUS_OK)
328       goto err;
329   }  
330
331   SILC_LOG_DEBUG(("Public key is authentic"));
332
333   /* Compute the hash value */
334   status = silc_ske_make_hash(ske, hash, &hash_len);
335   if (status != SILC_SKE_STATUS_OK)
336     goto err;
337
338   ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
339   memcpy(ske->hash, hash, hash_len);
340   ske->hash_len = hash_len;
341
342   SILC_LOG_DEBUG(("Verifying signature"));
343
344   /* Verify signature */
345   silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, 
346                                 public_key->pk_len);
347   if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
348                                     payload->sign_data, payload->sign_len,
349                                     hash, hash_len) == FALSE) {
350
351     SILC_LOG_DEBUG(("Signature don't match"));
352
353     status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
354     goto err;
355   }
356
357   SILC_LOG_DEBUG(("Signature is Ok"));
358
359   silc_pkcs_public_key_free(public_key);
360   memset(hash, 'F', hash_len);
361
362   /* Call the callback. */
363   if (callback)
364     (*callback)(ske, context);
365
366   return status;
367
368  err:
369   memset(hash, 'F', sizeof(hash));
370   silc_ske_payload_two_free(payload);
371   ske->ke2_payload = NULL;
372
373   silc_mp_clear(&ske->KEY);
374
375   if (public_key)
376     silc_pkcs_public_key_free(public_key);
377
378   if (ske->hash) {
379     memset(ske->hash, 'F', hash_len);
380     silc_free(ske->hash);
381     ske->hash = NULL;
382   }
383
384   if (status == SILC_SKE_STATUS_OK)
385     return SILC_SKE_STATUS_ERROR;
386
387   return status;
388 }
389
390 /* Starts Key Exchange protocol for responder. Responder receives
391    Key Exchange Start Payload from initiator consisting of all the
392    security properties the initiator supports. This function decodes
393    the payload and parses the payload further and selects the right 
394    security properties. */
395
396 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
397                                        SilcSocketConnection sock,
398                                        SilcBuffer start_payload,
399                                        SilcSKECb callback,
400                                        void *context)
401 {
402   SilcSKEStatus status = SILC_SKE_STATUS_OK;
403   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
404
405   SILC_LOG_DEBUG(("Start"));
406
407   ske->sock = sock;
408   ske->rng = rng;
409
410   /* Decode the payload */
411   status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
412   if (status != SILC_SKE_STATUS_OK)
413     return status;
414
415   /* Take a copy of the payload buffer for future use. It is used to
416      compute the HASH value. */
417   ske->start_payload_copy = silc_buffer_copy(start_payload);
418
419   /* Parse and select the security properties from the payload */
420   payload = silc_calloc(1, sizeof(*payload));
421   status = silc_ske_select_security_properties(ske, payload, remote_payload);
422   if (status != SILC_SKE_STATUS_OK)
423     goto err;
424
425   ske->start_payload = payload;
426
427   /* Call the callback function. */
428   if (callback)
429     (*callback)(ske, context);
430
431   return status;
432
433  err:
434   if (remote_payload)
435     silc_ske_payload_start_free(remote_payload);
436   if (payload)
437     silc_free(payload);
438
439   if (status == SILC_SKE_STATUS_OK)
440     return SILC_SKE_STATUS_ERROR;
441
442   return status;
443 }
444
445 /* The selected security properties from the initiator payload is now 
446    encoded into Key Exchange Start Payload and sent to the initiator. */
447
448 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
449                                          SilcSKEStartPayload *start_payload,
450                                          SilcSKESendPacketCb send_packet,
451                                          void *context)
452 {
453   SilcSKEStatus status = SILC_SKE_STATUS_OK;
454   SilcBuffer payload_buf;
455   SilcSKESecurityProperties prop;
456   SilcSKEDiffieHellmanGroup group;
457
458   SILC_LOG_DEBUG(("Start"));
459
460   /* Allocate security properties from the payload. These are allocated
461      only for this negotiation and will be free'd after KE is over. */
462   ske->prop = prop = silc_calloc(1, sizeof(*prop));
463   prop->flags = start_payload->flags;
464   status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
465   if (status != SILC_SKE_STATUS_OK)
466     goto err;
467
468   prop->group = group;
469
470   if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
471                       &prop->pkcs) == FALSE) {
472     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
473     goto err;
474   }
475
476   if (silc_cipher_alloc(start_payload->enc_alg_list, 
477                         &prop->cipher) == FALSE) {
478     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
479     goto err;
480   }
481
482   if (silc_hash_alloc(start_payload->hash_alg_list,
483                       &prop->hash) == FALSE) {
484     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
485     goto err;
486   }
487
488   /* Encode the payload */
489   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
490   if (status != SILC_SKE_STATUS_OK)
491     goto err;
492
493   /* Send the packet. */
494   if (send_packet)
495     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
496
497   silc_buffer_free(payload_buf);
498
499   return status;
500
501  err:
502   silc_free(group);
503
504   if (prop->pkcs)
505     silc_pkcs_free(prop->pkcs);
506   if (prop->cipher)
507     silc_cipher_free(prop->cipher);
508   if (prop->hash)
509     silc_hash_free(prop->hash);
510   silc_free(prop);
511   ske->prop = NULL;
512
513   if (status == SILC_SKE_STATUS_OK)
514     return SILC_SKE_STATUS_ERROR;
515
516   return status;
517 }
518
519 /* This function receives the Key Exchange 1 Payload from the initiator.
520    After processing the payload this then selects random number x,
521    such that 1 < x < q and computes f = g ^ x mod p. This then puts
522    the result f to a Key Exchange 2 Payload which is later processed
523    in ske_responder_finish function. The callback function should
524    not touch the payload (it should merely call the ske_responder_finish
525    function). */
526
527 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
528                                          SilcBuffer ke1_payload,
529                                          SilcSKECb callback,
530                                          void *context)
531 {
532   SilcSKEStatus status = SILC_SKE_STATUS_OK;
533   SilcSKEOnePayload *one_payload;
534   SilcSKETwoPayload *two_payload;
535   SilcInt x, f;
536
537   SILC_LOG_DEBUG(("Start"));
538
539   /* Decode Key Exchange 1 Payload */
540   status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
541   if (status != SILC_SKE_STATUS_OK)
542     return status;
543
544   /* Create the random number x, 1 < x < q. */
545   silc_mp_init(&x);
546   status = 
547     silc_ske_create_rnd(ske, ske->prop->group->group_order,
548                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
549                         &x);
550   if (status != SILC_SKE_STATUS_OK) {
551     silc_mp_clear(&x);
552     return status;
553   }
554
555   SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
556
557   /* Do the Diffie Hellman computation, f = g ^ x mod p */
558   silc_mp_init(&f);
559   silc_mp_powm(&f, &ske->prop->group->generator, &x, 
560                &ske->prop->group->group);
561   
562   /* Save the results for later processing */
563   two_payload = silc_calloc(1, sizeof(*two_payload));
564   two_payload->f = f;
565   ske->x = x;
566   ske->ke1_payload = one_payload;
567   ske->ke2_payload = two_payload;
568
569   /* Call the callback. */
570   if (callback)
571     (*callback)(ske, context);
572
573   return status;
574 }
575
576 /* This function computes the secret shared key KEY = e ^ x mod p, and, 
577    a hash value to be signed and sent to the other end. This then
578    encodes Key Exchange 2 Payload and sends it to the other end. */
579
580 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
581                                         SilcPublicKey public_key,
582                                         SilcPrivateKey private_key,
583                                         SilcSKEPKType pk_type,
584                                         SilcSKESendPacketCb send_packet,
585                                         void *context)
586 {
587   SilcSKEStatus status = SILC_SKE_STATUS_OK;
588   SilcBuffer payload_buf;
589   SilcInt KEY;
590   unsigned char hash[32], sign[256], *pk;
591   unsigned int hash_len, sign_len, pk_len;
592
593   SILC_LOG_DEBUG(("Start"));
594
595   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
596
597   /* Compute the shared secret key */
598   silc_mp_init(&KEY);
599   silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x, 
600                &ske->prop->group->group);
601   ske->KEY = KEY;
602
603   SILC_LOG_DEBUG(("Getting public key"));
604
605   /* Get the public key */
606   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
607   ske->ke2_payload->pk_data = pk;
608   ske->ke2_payload->pk_len = pk_len;
609   ske->ke2_payload->pk_type = pk_type;
610
611   SILC_LOG_DEBUG(("Computing HASH value"));
612
613   /* Compute the hash value */
614   memset(hash, 0, sizeof(hash));
615   status = silc_ske_make_hash(ske, hash, &hash_len);
616   if (status != SILC_SKE_STATUS_OK)
617     goto err;
618
619   ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
620   memcpy(ske->hash, hash, hash_len);
621   ske->hash_len = hash_len;
622
623   SILC_LOG_DEBUG(("Signing HASH value"));
624
625   /* Sign the hash value */
626   silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
627                                  private_key->prv_len);
628   ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
629                               hash, hash_len,
630                               sign, &sign_len);
631   ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
632   memcpy(ske->ke2_payload->sign_data, sign, sign_len);
633   memset(sign, 0, sizeof(sign));
634   ske->ke2_payload->sign_len = sign_len;
635
636   /* Encode the Key Exchange 2 Payload */
637   status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
638                                        &payload_buf);
639   if (status != SILC_SKE_STATUS_OK)
640     goto err;
641
642   /* Send the packet. */
643   if (send_packet)
644     (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
645
646   silc_buffer_free(payload_buf);
647
648   return status;
649
650  err:
651   silc_mp_clear(&ske->KEY);
652   silc_ske_payload_two_free(ske->ke2_payload);
653
654   if (status == SILC_SKE_STATUS_OK)
655     return SILC_SKE_STATUS_ERROR;
656
657   return status;
658 }
659
660 /* The Key Exchange protocol is ended by calling this function. This
661    must not be called until the keys are processed like the protocol
662    defines. This function is for both initiator and responder. */
663
664 SilcSKEStatus silc_ske_end(SilcSKE ske,
665                            SilcSKESendPacketCb send_packet,
666                            void *context)
667 {
668   SilcSKEStatus status = SILC_SKE_STATUS_OK;
669   SilcBuffer packet;
670
671   SILC_LOG_DEBUG(("Start"));
672
673   packet = silc_buffer_alloc(1);
674   packet->len = 0;
675
676   if (send_packet)
677     (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
678
679   return status;
680 }
681
682 /* Aborts the Key Exchange protocol. This is called if error occurs
683    while performing the protocol. The status argument is the error
684    status and it is sent to the remote end. */
685
686 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
687                              SilcSKESendPacketCb send_packet,
688                              void *context)
689 {
690   SilcBuffer packet;
691
692   SILC_LOG_DEBUG(("Start"));
693
694   packet = silc_buffer_alloc(4);
695   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
696   silc_buffer_format(packet,
697                      SILC_STR_UI_SHORT(status),
698                      SILC_STR_END);
699
700   if (send_packet)
701     (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
702
703   silc_buffer_free(packet);
704
705   return SILC_SKE_STATUS_OK;
706 }
707
708 /* Assembles security properties to Key Exchange Start Payload to be
709    sent to the remote end. This checks system wide (SILC system, that is)
710    settings and chooses from those. However, if other properties
711    should be used this function is easy to replace by another function,
712    as, this function is called by the caller of the protocol and not
713    by the protocol itself. */
714
715 SilcSKEStatus 
716 silc_ske_assemble_security_properties(SilcSKE ske,
717                                       SilcSKEStartPayload **return_payload)
718 {
719   SilcSKEStartPayload *rp;
720
721   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
722
723   rp = silc_calloc(1, sizeof(*rp));
724
725   /* XXX */
726   /* Set flags */
727   rp->flags = 0;
728
729   /* XXX */
730   /* Cookie */
731   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
732   rp->cookie_len = SILC_SKE_COOKIE_LEN;
733   memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
734
735   /* Get supported Key Exhange groups */
736   rp->ke_grp_list = silc_ske_get_supported_groups();
737   rp->ke_grp_len = strlen(rp->ke_grp_list);
738
739   /* Get supported PKCS algorithms */
740   rp->pkcs_alg_list = silc_pkcs_get_supported();
741   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
742
743   /* Get supported encryption algorithms */
744   rp->enc_alg_list = silc_cipher_get_supported();
745   rp->enc_alg_len = strlen(rp->enc_alg_list);
746
747   /* Get supported hash algorithms */
748   rp->hash_alg_list = silc_hash_get_supported();
749   rp->hash_alg_len = strlen(rp->hash_alg_list);
750
751   /* XXX */
752   /* Get supported compression algorithms */
753   rp->comp_alg_list = "";
754   rp->comp_alg_len = 0;
755
756   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
757     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
758     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
759     2 + rp->comp_alg_len;
760
761   *return_payload = rp;
762
763   return SILC_SKE_STATUS_OK;
764 }
765
766 /* Selects the supported security properties from the remote end's Key 
767    Exchange Start Payload. */
768
769 SilcSKEStatus 
770 silc_ske_select_security_properties(SilcSKE ske,
771                                     SilcSKEStartPayload *payload,
772                                     SilcSKEStartPayload *remote_payload)
773 {
774   SilcSKEStartPayload *rp;
775   char *cp;
776   int len;
777
778   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
779
780   rp = remote_payload;
781
782   /* Flags are returned unchanged. */
783   payload->flags = rp->flags;
784
785   /* XXX Cookie check?? */
786   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
787   payload->cookie_len = SILC_SKE_COOKIE_LEN;
788   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
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->ke_grp_len + 2 + payload->pkcs_alg_len + 
1049     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1050     2 + payload->comp_alg_len;
1051
1052   return SILC_SKE_STATUS_OK;
1053 }
1054
1055 /* Creates random number such that 1 < rnd < n and at most length
1056    of len bits. The rnd sent as argument must be initialized. */
1057
1058 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
1059                                   unsigned int len, 
1060                                   SilcInt *rnd)
1061 {
1062   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1063   unsigned char *string;
1064
1065   SILC_LOG_DEBUG(("Creating random number"));
1066
1067   /* Get the random number as string */
1068   string = silc_rng_get_rn_data(ske->rng, (len / 8));
1069
1070   /* Decode the string into a MP integer */
1071   silc_mp_bin2mp(string, (len / 8), rnd);
1072   silc_mp_mod_2exp(rnd, rnd, len);
1073
1074   /* Checks */
1075   if (silc_mp_cmp_ui(rnd, 1) < 0)
1076     status = SILC_SKE_STATUS_ERROR;
1077
1078   if (silc_mp_cmp(rnd, &n) >= 0)
1079     status = SILC_SKE_STATUS_ERROR;
1080
1081   memset(string, 'F', (len / 8));
1082   silc_free(string);
1083
1084   return status;
1085 }
1086
1087 /* Creates a hash value HASH as defined in the SKE protocol. */
1088
1089 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1090                                  unsigned char *return_hash,
1091                                  unsigned int *return_hash_len)
1092 {
1093   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1094   SilcBuffer buf;
1095   unsigned char *e, *f, *KEY;
1096   unsigned int e_len, f_len, KEY_len;
1097
1098   SILC_LOG_DEBUG(("Start"));
1099
1100   e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1101   f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1102   KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
1103
1104   buf = silc_buffer_alloc(ske->start_payload_copy->len + 
1105                           ske->pk_len + e_len + f_len + KEY_len);
1106   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1107
1108   /* Format the buffer used to compute the hash value */
1109   silc_buffer_format(buf,
1110                      SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1111                                           ske->start_payload_copy->len),
1112                      SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1113                      SILC_STR_UI_XNSTRING(e, e_len),
1114                      SILC_STR_UI_XNSTRING(f, f_len),
1115                      SILC_STR_UI_XNSTRING(KEY, KEY_len),
1116                      SILC_STR_END);
1117
1118 #if 0
1119   SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1120 #endif
1121
1122   /* Make the hash */
1123   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1124   *return_hash_len = ske->prop->hash->hash->hash_len;
1125
1126   SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1127
1128   silc_buffer_free(buf);
1129   memset(e, 0, e_len);
1130   memset(f, 0, f_len);
1131   memset(KEY, 0, KEY_len);
1132   silc_free(e);
1133   silc_free(f);
1134   silc_free(KEY);
1135
1136   return status;
1137 }
1138
1139 /* Processes negotiated key material as protocol specifies. This returns
1140    the actual keys to be used in the SILC. */
1141
1142 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1143                                             unsigned int req_iv_len,
1144                                             unsigned int req_enc_key_len,
1145                                             unsigned int req_hmac_key_len,
1146                                             SilcSKEKeyMaterial *key)
1147 {
1148   int klen;
1149   SilcBuffer buf;
1150   unsigned char *tmpbuf;
1151   unsigned char hash[32];
1152   unsigned int hash_len = ske->prop->hash->hash->hash_len;
1153   unsigned int enc_key_len = req_enc_key_len / 8;
1154
1155   SILC_LOG_DEBUG(("Start"));
1156
1157   /* Encode KEY to binary data */
1158   tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
1159
1160   buf = silc_buffer_alloc(1 + klen + hash_len);
1161   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1162   silc_buffer_format(buf,
1163                      SILC_STR_UI_CHAR(0),
1164                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
1165                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1166                      SILC_STR_END);
1167
1168   /* Take IVs */
1169   memset(hash, 0, sizeof(hash));
1170   buf->data[0] = 0;
1171   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1172   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1173   memcpy(key->send_iv, hash, req_iv_len);
1174   memset(hash, 0, sizeof(hash));
1175   buf->data[0] = 1;
1176   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1177   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1178   memcpy(key->receive_iv, hash, req_iv_len);
1179   key->iv_len = req_iv_len;
1180
1181   /* Take the encryption keys. If requested key size is more than
1182      the size of hash length we will distribute more key material
1183      as protocol defines. */
1184   buf->data[0] = 2;
1185   if (enc_key_len > hash_len) {
1186     SilcBuffer dist;
1187     unsigned char k1[32], k2[32], k3[32];
1188     unsigned char *dtmp;
1189     
1190     /* XXX */
1191     if (enc_key_len > (3 * hash_len))
1192       return SILC_SKE_STATUS_ERROR;
1193     
1194     memset(k1, 0, sizeof(k1));
1195     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1196     
1197     /* XXX */
1198     dist = silc_buffer_alloc(hash_len * 3);
1199     
1200     silc_buffer_pull_tail(dist, klen + hash_len);
1201     silc_buffer_format(dist,
1202                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1203                        SILC_STR_UI_XNSTRING(k1, hash_len),
1204                        SILC_STR_END);
1205     
1206     memset(k2, 0, sizeof(k2));
1207     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1208     
1209     silc_buffer_pull(dist, klen + hash_len);
1210     silc_buffer_format(dist,
1211                        SILC_STR_UI_XNSTRING(k2, hash_len),
1212                        SILC_STR_END);
1213     silc_buffer_push(dist, klen + hash_len);
1214     
1215     memset(k3, 0, sizeof(k3));
1216     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1217     
1218     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1219     memcpy(dtmp, k1, hash_len);
1220     memcpy(dtmp + hash_len, k2, hash_len);
1221     memcpy(dtmp + hash_len, k3, hash_len);
1222
1223     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1224     memcpy(key->send_enc_key, dtmp, enc_key_len);
1225     key->enc_key_len = req_enc_key_len;
1226
1227     memset(dtmp, 0, (3 * hash_len));
1228     memset(k1, 0, sizeof(k1));
1229     memset(k2, 0, sizeof(k2));
1230     memset(k3, 0, sizeof(k3));
1231     silc_free(dtmp);
1232     silc_buffer_free(dist);
1233   } else {
1234     /* Take normal hash as key */
1235     memset(hash, 0, sizeof(hash));
1236     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1237     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1238     memcpy(key->send_enc_key, hash, enc_key_len);
1239     key->enc_key_len = req_enc_key_len;
1240   }
1241
1242   buf->data[0] = 3;
1243   if (enc_key_len > hash_len) {
1244     SilcBuffer dist;
1245     unsigned char k1[32], k2[32], k3[32];
1246     unsigned char *dtmp;
1247     
1248     /* XXX */
1249     if (enc_key_len > (3 * hash_len))
1250       return SILC_SKE_STATUS_ERROR;
1251     
1252     memset(k1, 0, sizeof(k1));
1253     silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1254     
1255     /* XXX */
1256     dist = silc_buffer_alloc(hash_len * 3);
1257     
1258     silc_buffer_pull_tail(dist, klen + hash_len);
1259     silc_buffer_format(dist,
1260                        SILC_STR_UI_XNSTRING(tmpbuf, klen),
1261                        SILC_STR_UI_XNSTRING(k1, hash_len),
1262                        SILC_STR_END);
1263     
1264     memset(k2, 0, sizeof(k2));
1265     silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1266     
1267     silc_buffer_pull(dist, klen + hash_len);
1268     silc_buffer_format(dist,
1269                        SILC_STR_UI_XNSTRING(k2, hash_len),
1270                        SILC_STR_END);
1271     silc_buffer_push(dist, klen + hash_len);
1272     
1273     memset(k3, 0, sizeof(k3));
1274     silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1275     
1276     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1277     memcpy(dtmp, k1, hash_len);
1278     memcpy(dtmp + hash_len, k2, hash_len);
1279     memcpy(dtmp + hash_len, k3, hash_len);
1280
1281     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1282     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1283     key->enc_key_len = req_enc_key_len;
1284
1285     memset(dtmp, 0, (3 * hash_len));
1286     memset(k1, 0, sizeof(k1));
1287     memset(k2, 0, sizeof(k2));
1288     memset(k3, 0, sizeof(k3));
1289     silc_free(dtmp);
1290     silc_buffer_free(dist);
1291   } else {
1292     /* Take normal hash as key */
1293     memset(hash, 0, sizeof(hash));
1294     silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1295     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1296     memcpy(key->receive_enc_key, hash, enc_key_len);
1297     key->enc_key_len = req_enc_key_len;
1298   }
1299
1300   /* Take HMAC key */
1301   memset(hash, 0, sizeof(hash));
1302   buf->data[0] = 4;
1303   silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1304   key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1305   memcpy(key->hmac_key, hash, req_hmac_key_len);
1306   key->hmac_key_len = req_hmac_key_len;
1307
1308   memset(tmpbuf, 0, klen);
1309   silc_free(tmpbuf);
1310
1311   return SILC_SKE_STATUS_OK;
1312 }