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