Global cosmetic change.
[silc.git] / lib / silcske / payload.c
1 /*
2
3   payload.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 /* XXX TODO: This is not optimized version and should be optimized! 
21    Use *_ALLOC buffer formatting in payload decodings! */
22 /*
23  * $Id$
24  * $Log$
25  * Revision 1.2  2000/07/05 06:05:15  priikone
26  *      Global cosmetic change.
27  *
28  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
29  *      Imported from internal CVS/Added Log headers.
30  *
31  *
32  */
33
34 #include "silcincludes.h"
35 #include "payload_internal.h"
36
37 /* Temporary buffer used in payload decoding */
38 unsigned char buf[16384];
39
40 /* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
41    to the other end. */
42
43 SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
44                                             SilcSKEStartPayload *payload,
45                                             SilcBuffer *return_buffer)
46 {
47   SilcBuffer buf;
48
49   SILC_LOG_DEBUG(("Encoding KE Start Payload"));
50
51   if (!payload)
52     return SILC_SKE_STATUS_ERROR;
53
54   /* Allocate channel payload buffer. */
55   buf = silc_buffer_alloc(payload->len);
56
57   silc_buffer_pull_tail(buf, payload->len);
58
59   /* Encode the payload */
60   silc_buffer_format(buf,
61                      SILC_STR_UI_CHAR(0),        /* RESERVED field */
62                      SILC_STR_UI_CHAR(payload->flags),
63                      SILC_STR_UI_SHORT(payload->len),
64                      SILC_STR_UI_XNSTRING(payload->cookie, 
65                                           payload->cookie_len),
66                      SILC_STR_UI_SHORT(payload->ke_grp_len),
67                      SILC_STR_UI_XNSTRING(payload->ke_grp_list,
68                                           payload->ke_grp_len),
69                      SILC_STR_UI_SHORT(payload->pkcs_alg_len),
70                      SILC_STR_UI_XNSTRING(payload->pkcs_alg_list,
71                                           payload->pkcs_alg_len),
72                      SILC_STR_UI_SHORT(payload->enc_alg_len),
73                      SILC_STR_UI_XNSTRING(payload->enc_alg_list,
74                                           payload->enc_alg_len),
75                      SILC_STR_UI_SHORT(payload->hash_alg_len),
76                      SILC_STR_UI_XNSTRING(payload->hash_alg_list,
77                                           payload->hash_alg_len),
78                      SILC_STR_UI_SHORT(payload->comp_alg_len),
79                      SILC_STR_UI_XNSTRING(payload->comp_alg_list,
80                                           payload->comp_alg_len),
81                      SILC_STR_END);
82
83   /* Return the encoded buffer */
84   *return_buffer = buf;
85
86   SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, buf->len);
87
88   return SILC_SKE_STATUS_OK;
89 }
90
91 /* Parses the Key Exchange Start Payload. Parsed data is returned
92    to allocated payload structure. */
93
94 SilcSKEStatus 
95 silc_ske_payload_start_decode(SilcSKE ske,
96                               SilcBuffer buffer,
97                               SilcSKEStartPayload **return_payload)
98 {
99   SilcSKEStartPayload *payload;
100   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
101   unsigned char tmp;
102   int len, len2;
103
104   SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
105
106   SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, buffer->len);
107
108   payload = silc_calloc(1, sizeof(*payload));
109   memset(buf, 0, sizeof(buf));
110
111   /* Parse the entire payload */
112   silc_buffer_unformat(buffer,
113                        SILC_STR_UI_CHAR(&tmp),     /* RESERVED Field */
114                        SILC_STR_UI_CHAR(&payload->flags),
115                        SILC_STR_UI_SHORT(&payload->len),
116                        SILC_STR_UI_XNSTRING(&buf, SILC_SKE_COOKIE_LEN),
117                        SILC_STR_UI_SHORT(&payload->ke_grp_len),
118                        SILC_STR_END);
119
120   if (tmp != 0) {
121     SILC_LOG_DEBUG(("Bad reserved field"));
122     status = SILC_SKE_STATUS_BAD_RESERVED_FIELD;
123     goto err;
124   }
125
126   if (payload->len != buffer->len) {
127     SILC_LOG_DEBUG(("Bad payload length"));
128     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
129     goto err;
130   }
131
132   if (payload->ke_grp_len < 1) {
133     SILC_LOG_DEBUG(("Bad payload length"));
134     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
135     goto err;
136   }
137
138   len2 = len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 2;
139   silc_buffer_pull(buffer, len);
140
141   /* Copy cookie from payload */
142   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, 
143                                 sizeof(unsigned char));
144   payload->cookie_len = SILC_SKE_COOKIE_LEN;
145   memcpy(payload->cookie, buf, SILC_SKE_COOKIE_LEN);
146   memset(buf, 0, sizeof(buf));
147
148   silc_buffer_unformat(buffer,
149                        SILC_STR_UI_XNSTRING(&buf, payload->ke_grp_len),
150                        SILC_STR_UI_SHORT(&payload->pkcs_alg_len),
151                        SILC_STR_END);
152
153   if (payload->pkcs_alg_len < 1) {
154     SILC_LOG_DEBUG(("Bad payload length"));
155     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
156     goto err;
157   }
158
159   len2 += len = payload->ke_grp_len + 2;
160   silc_buffer_pull(buffer, len);
161
162   /* Copy KE groups from payload */
163   payload->ke_grp_list = silc_calloc(payload->ke_grp_len + 1, 
164                                      sizeof(unsigned char));
165   memcpy(payload->ke_grp_list, buf, payload->ke_grp_len);
166   memset(buf, 0, sizeof(buf));
167
168   silc_buffer_unformat(buffer,
169                        SILC_STR_UI_XNSTRING(&buf, payload->pkcs_alg_len),
170                        SILC_STR_UI_SHORT(&payload->enc_alg_len),
171                        SILC_STR_END);
172
173   if (payload->enc_alg_len < 1) {
174     SILC_LOG_DEBUG(("Bad payload length"));
175     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
176     goto err;
177   }
178
179   len2 += len = payload->pkcs_alg_len + 2;
180   silc_buffer_pull(buffer, len);
181
182   /* Copy PKCS algs from payload */
183   payload->pkcs_alg_list = silc_calloc(payload->pkcs_alg_len + 1, 
184                                        sizeof(unsigned char));
185   memcpy(payload->pkcs_alg_list, buf, payload->pkcs_alg_len);
186   memset(buf, 0, sizeof(buf));
187
188   silc_buffer_unformat(buffer,
189                        SILC_STR_UI_XNSTRING(&buf, payload->enc_alg_len),
190                        SILC_STR_UI_SHORT(&payload->hash_alg_len),
191                        SILC_STR_END);
192
193   if (payload->hash_alg_len < 1) {
194     SILC_LOG_DEBUG(("Bad payload length"));
195     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
196     goto err;
197   }
198
199   len2 += len = payload->enc_alg_len + 2;
200   silc_buffer_pull(buffer, len);
201
202   /* Copy encryption algs from payload */
203   payload->enc_alg_list = silc_calloc(payload->enc_alg_len + 1, 
204                                       sizeof(unsigned char));
205   memcpy(payload->enc_alg_list, buf, payload->enc_alg_len);
206   memset(buf, 0, sizeof(buf));
207
208   silc_buffer_unformat(buffer,
209                        SILC_STR_UI_XNSTRING(&buf, payload->hash_alg_len),
210                        SILC_STR_UI_SHORT(&payload->comp_alg_len),
211                        SILC_STR_END);
212
213   len2 += len = payload->hash_alg_len + 2;
214   silc_buffer_pull(buffer, len);
215
216   /* Copy hash algs from payload */
217   payload->hash_alg_list = silc_calloc(payload->hash_alg_len + 1, 
218                                        sizeof(unsigned char));
219   memcpy(payload->hash_alg_list, buf, payload->hash_alg_len);
220   memset(buf, 0, sizeof(buf));
221
222   if (payload->comp_alg_len) {
223     silc_buffer_unformat(buffer,
224                          SILC_STR_UI_XNSTRING(&buf, payload->comp_alg_len),
225                          SILC_STR_END);
226
227     /* Copy compression algs from payload */
228     payload->comp_alg_list = silc_calloc(payload->comp_alg_len + 1, 
229                                          sizeof(unsigned char));
230     memcpy(payload->comp_alg_list, buf, payload->comp_alg_len);
231     memset(buf, 0, sizeof(buf));
232   }
233
234   silc_buffer_push(buffer, len2);
235
236   /* Return the payload */
237   *return_payload = payload;
238
239   return SILC_SKE_STATUS_OK;
240
241  err:
242   silc_ske_payload_start_free(payload);
243
244   return status;
245 }
246
247 /* Free's Start Payload */
248
249 void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
250 {
251   if (payload) {
252     if (payload->cookie)
253       silc_free(payload->cookie);
254     if (payload->ke_grp_list)
255       silc_free(payload->ke_grp_list);
256     if (payload->pkcs_alg_list)
257       silc_free(payload->pkcs_alg_list);
258     if (payload->enc_alg_list)
259       silc_free(payload->enc_alg_list);
260     if (payload->hash_alg_list)
261       silc_free(payload->hash_alg_list);
262     if (payload->comp_alg_list)
263       silc_free(payload->comp_alg_list);
264     silc_free(payload);
265   }
266 }
267
268 /* Encodes Key Exchange 1 Payload into a SILC Buffer to be sent
269    to the other end. */
270
271 SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
272                                           SilcSKEOnePayload *payload,
273                                           SilcBuffer *return_buffer)
274 {
275   SilcBuffer buf;
276   unsigned char *e_str;
277   unsigned short e_len;
278
279   SILC_LOG_DEBUG(("Encoding KE 1 Payload"));
280
281   if (!payload)
282     return SILC_SKE_STATUS_ERROR;
283
284   /* Encode the integer into HEX string */
285   e_len = silc_mp_sizeinbase(&payload->e, 16);
286   e_str = silc_calloc(e_len + 1, sizeof(unsigned char));
287   silc_mp_get_str(e_str, 16, &payload->e);
288
289   /* Allocate channel payload buffer. The length of the buffer
290      is 2 + e. */
291   buf = silc_buffer_alloc(e_len + 2);
292
293   silc_buffer_pull_tail(buf, e_len + 2);
294
295   /* Encode the payload */
296   silc_buffer_format(buf, 
297                      SILC_STR_UI_SHORT(e_len + 2),
298                      SILC_STR_UI_XNSTRING(e_str, e_len),
299                      SILC_STR_END);
300
301   /* Return encoded buffer */
302   *return_buffer = buf;
303
304   memset(e_str, 'F', e_len);
305   silc_free(e_str);
306
307   return SILC_SKE_STATUS_OK;
308 }
309
310 /* Parses the Key Exchange 1 Payload. Parsed data is returned
311    to allocated payload structure. */
312
313 SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
314                                           SilcBuffer buffer,
315                                           SilcSKEOnePayload **return_payload)
316 {
317   SilcSKEOnePayload *payload;
318   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
319   unsigned short e_len;
320
321   SILC_LOG_DEBUG(("Decoding Key Exchange 1 Payload"));
322
323   SILC_LOG_HEXDUMP(("KE 1 Payload"), buffer->data, buffer->len);
324
325   payload = silc_calloc(1, sizeof(*payload));
326
327   memset(buf, 0, sizeof(buf));
328
329   /* Parse the payload */
330   silc_buffer_unformat(buffer,
331                        SILC_STR_UI_SHORT(&e_len),
332                        SILC_STR_END);
333                        
334   if (e_len < 1) {
335     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
336     goto err;
337   }
338
339   if (e_len != buffer->len) {
340     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
341     goto err;
342   }
343
344   /* Length includes the length field length as well. Remove it. */
345   e_len -= 2;
346
347   silc_buffer_unformat(buffer,
348                        SILC_STR_UI_SHORT(NULL),
349                        SILC_STR_UI_XNSTRING(&buf, e_len),
350                        SILC_STR_END);
351
352   /* Decode the HEX string to integer */
353   silc_mp_init(&payload->e);
354   silc_mp_set_str(&payload->e, buf, 16);
355   memset(buf, 0, sizeof(buf));
356
357   /* Return the payload */
358   *return_payload = payload;
359
360   return SILC_SKE_STATUS_OK;
361
362  err:
363   silc_free(payload);
364
365   return status;
366 }
367
368 /* Free's KE1 Payload */
369
370 void silc_ske_payload_one_free(SilcSKEOnePayload *payload)
371 {
372   if (payload) {
373     silc_mp_clear(&payload->e);
374     silc_free(payload);
375   }
376 }
377
378 /* Encodes Key Exchange 2 Payload into a SILC Buffer to be sent
379    to the other end. */
380
381 SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
382                                           SilcSKETwoPayload *payload,
383                                           SilcBuffer *return_buffer)
384 {
385   SilcBuffer buf;
386   unsigned char *f_str;
387   unsigned int f_len;
388   unsigned int len;
389
390   SILC_LOG_DEBUG(("Encoding KE 2 Payload"));
391
392   if (!payload)
393     return SILC_SKE_STATUS_ERROR;
394
395   /* Encode the integer into HEX string */
396   f_len = silc_mp_sizeinbase(&payload->f, 16);
397   f_str = silc_calloc(f_len + 1, sizeof(unsigned char));
398   silc_mp_get_str(f_str, 16, &payload->f);
399
400   /* Allocate channel payload buffer. The length of the buffer
401      is 2 + 2 + public key + 2 + f + 2 + signature. */
402   len = payload->pk_len + 2 + 2 + f_len + 2 + payload->sign_len + 2;
403   buf = silc_buffer_alloc(len);
404
405   silc_buffer_pull_tail(buf, len);
406
407   /* Encode the payload */
408   silc_buffer_format(buf, 
409                      SILC_STR_UI_SHORT(payload->pk_len + 4),
410                      SILC_STR_UI_SHORT(payload->pk_type),
411                      SILC_STR_UI_XNSTRING(payload->pk_data, 
412                                           payload->pk_len),
413                      SILC_STR_UI_SHORT(f_len + 2),
414                      SILC_STR_UI_XNSTRING(f_str, f_len),
415                      SILC_STR_UI_SHORT(payload->sign_len + 2),
416                      SILC_STR_UI_XNSTRING(payload->sign_data, 
417                                           payload->sign_len),
418                      SILC_STR_END);
419
420   /* Return encoded buffer */
421   *return_buffer = buf;
422
423   memset(f_str, 'F', f_len);
424   silc_free(f_str);
425
426   return SILC_SKE_STATUS_OK;
427 }
428
429 /* Parses the Key Exchange 2 Payload. Parsed data is returned
430    to allocated payload structure. */
431
432 SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
433                                           SilcBuffer buffer,
434                                           SilcSKETwoPayload **return_payload)
435 {
436   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
437   SilcSKETwoPayload *payload;
438   unsigned short f_len;
439   unsigned int tot_len = 0, len2;
440
441   SILC_LOG_DEBUG(("Decoding Key Exchange 2 Payload"));
442
443   SILC_LOG_HEXDUMP(("KE 2 Payload"), buffer->data, buffer->len);
444
445   payload = silc_calloc(1, sizeof(*payload));
446   memset(buf, 0, sizeof(buf));
447
448   len2 = buffer->len;
449
450   /* Parse the payload */
451   silc_buffer_unformat(buffer,
452                        SILC_STR_UI_SHORT(&payload->pk_len),
453                        SILC_STR_UI_SHORT(&payload->pk_type),
454                        SILC_STR_END);
455
456   if (payload->pk_len < 5) {
457     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
458     goto err;
459   }
460
461   tot_len += payload->pk_len;
462
463   payload->pk_len -= 4;
464   silc_buffer_pull(buffer, 4);
465   silc_buffer_unformat(buffer,
466                        SILC_STR_UI_XNSTRING(&buf, payload->pk_len),
467                        SILC_STR_UI_SHORT(&f_len),
468                        SILC_STR_END);
469
470   if (f_len < 3) {
471     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
472     goto err;
473   }
474
475   tot_len += f_len;
476
477   payload->pk_data = silc_calloc(payload->pk_len + 1, 
478                                  sizeof(unsigned char));
479   memcpy(payload->pk_data, buf, payload->pk_len);
480   memset(buf, 0, sizeof(buf));
481
482   f_len -= 2;
483   silc_buffer_pull(buffer, payload->pk_len + 2);
484   silc_buffer_unformat(buffer,
485                        SILC_STR_UI_XNSTRING(&buf, f_len),
486                        SILC_STR_UI_SHORT(&payload->sign_len),
487                        SILC_STR_END);
488
489   if (payload->sign_len < 3) {
490     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
491     goto err;
492   }
493
494   tot_len += payload->sign_len;
495
496   if (tot_len != len2) {
497     status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
498     goto err;
499   }
500   
501   /* Decode the HEX string to integer */
502   silc_mp_init(&payload->f);
503   silc_mp_set_str(&payload->f, buf, 16);
504   memset(buf, 0, sizeof(buf));
505
506   payload->sign_len -= 2;
507   silc_buffer_pull(buffer, f_len + 2);
508   silc_buffer_unformat(buffer,
509                        SILC_STR_UI_XNSTRING(&buf, payload->sign_len),
510                        SILC_STR_END);
511
512   payload->sign_data = silc_calloc(payload->sign_len + 1, 
513                                  sizeof(unsigned char));
514   memcpy(payload->sign_data, buf, payload->sign_len);
515   memset(buf, 0, sizeof(buf));
516
517   /* Return the payload */
518   *return_payload = payload;
519
520   return SILC_SKE_STATUS_OK;
521
522  err:
523   if (payload->pk_data)
524     silc_free(payload->pk_data);
525   if (payload->sign_data)
526     silc_free(payload->sign_data);
527   silc_free(payload);
528
529   return status;
530 }
531
532 /* Free's KE2 Payload */
533
534 void silc_ske_payload_two_free(SilcSKETwoPayload *payload)
535 {
536   if (payload) {
537     if (payload->pk_data)
538       silc_free(payload->pk_data);
539     if (payload->sign_data)
540       silc_free(payload->sign_data);
541     silc_mp_clear(&payload->f);
542     silc_free(payload);
543   }
544 }