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