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