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