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