updates. New data types.
[silc.git] / lib / silccore / silcchannel.c
1 /*
2
3   silcchannel.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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 /* Channel Payload, Channel Message Payload and Channel Key Payload 
21    implementations. */
22 /* $Id$ */
23
24 #include "silcincludes.h"
25 #include "silcchannel.h"
26
27 /******************************************************************************
28
29                               Channel Payload
30
31 ******************************************************************************/
32
33 /* Channel Message Payload structure. Contents of this structure is parsed
34    from SILC packets. */
35 struct SilcChannelPayloadStruct {
36   uint16 name_len;
37   unsigned char *channel_name;
38   uint16 id_len;
39   unsigned char *channel_id;
40   uint32 mode;
41 };
42
43 /* Parses channel payload returning new channel payload structure. */
44
45 SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer)
46 {
47   SilcChannelPayload new;
48   int ret;
49
50   SILC_LOG_DEBUG(("Parsing channel payload"));
51
52   new = silc_calloc(1, sizeof(*new));
53
54   /* Parse the Channel Payload. Ignore the padding. */
55   ret = silc_buffer_unformat(buffer,
56                              SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name, 
57                                                          &new->name_len),
58                              SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id, 
59                                                          &new->id_len),
60                              SILC_STR_UI_INT(&new->mode),
61                              SILC_STR_END);
62   if (ret == -1)
63     goto err;
64
65   if ((new->name_len < 1 || new->name_len > buffer->len) ||
66       (new->id_len < 1 || new->id_len > buffer->len)) {
67     SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
68     goto err;
69   }
70
71   return new;
72
73  err:
74   silc_channel_payload_free(new);
75   return NULL;
76 }
77
78 /* Parses list of channel payloads returning list of payloads. */
79
80 SilcDList silc_channel_payload_parse_list(SilcBuffer buffer)
81 {
82   SilcDList list;
83   SilcChannelPayload new;
84   int len, ret;
85
86   SILC_LOG_DEBUG(("Parsing channel payload list"));
87
88   list = silc_dlist_init();
89
90   while (buffer->len) {
91     new = silc_calloc(1, sizeof(*new));
92     ret = silc_buffer_unformat(buffer,
93                                SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name, 
94                                                            &new->name_len),
95                                SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id, 
96                                                            &new->id_len),
97                                SILC_STR_UI_INT(&new->mode),
98                                SILC_STR_END);
99     if (ret == -1)
100       goto err;
101
102     if ((new->name_len < 1 || new->name_len > buffer->len) ||
103         (new->id_len < 1 || new->id_len > buffer->len)) {
104       SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
105       goto err;
106     }
107
108     len = 2 + new->name_len + 2 + new->id_len + 4;
109     if (buffer->len < len)
110       break;
111     silc_buffer_pull(buffer, len);
112
113     silc_dlist_add(list, new);
114   }
115   
116   return list;
117
118  err:
119   silc_channel_payload_list_free(list);
120   return NULL;
121 }
122
123 /* Encode new channel payload and returns it as buffer. */
124
125 SilcBuffer silc_channel_payload_encode(unsigned char *channel_name,
126                                        uint16 channel_name_len,
127                                        unsigned char *channel_id,
128                                        uint32 channel_id_len,
129                                        uint32 mode)
130 {
131   SilcBuffer buffer;
132
133   SILC_LOG_DEBUG(("Encoding message payload"));
134
135   buffer = silc_buffer_alloc(2 + channel_name_len + 2 + channel_id_len + 4);
136   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
137
138   /* Encode the Channel Payload */
139   silc_buffer_format(buffer, 
140                      SILC_STR_UI_SHORT(channel_name_len),
141                      SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
142                      SILC_STR_UI_SHORT(channel_id_len),
143                      SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
144                      SILC_STR_UI_INT(mode),
145                      SILC_STR_END);
146
147   return buffer;
148 }
149
150 /* Free's Channel Payload */
151
152 void silc_channel_payload_free(SilcChannelPayload payload)
153 {
154   silc_free(payload->channel_name);
155   silc_free(payload->channel_id);
156   silc_free(payload);
157 }
158
159 /* Free's list of Channel Payloads */
160
161 void silc_channel_payload_list_free(SilcDList list)
162 {
163   SilcChannelPayload entry;
164
165   silc_dlist_start(list);
166   while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
167     silc_free(entry->channel_name);
168     silc_free(entry->channel_id);
169     silc_free(entry);
170     silc_dlist_del(list, entry);
171   }
172
173   silc_dlist_uninit(list);
174 }
175
176 /* Return the channel name */
177
178 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
179                                      uint32 *channel_name_len)
180 {
181   if (channel_name_len)
182     *channel_name_len = payload->name_len;
183
184   return payload->channel_name;
185 }
186
187 /* Return the channel ID */
188
189 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
190                                    uint32 *channel_id_len)
191 {
192   if (channel_id_len)
193     *channel_id_len = payload->id_len;
194
195   return payload->channel_id;
196 }
197
198 /* Return the channel ID as parsed ID. */
199
200 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
201 {
202   return silc_id_str2id(payload->channel_id, payload->id_len,
203                         SILC_ID_CHANNEL);
204 }
205
206 /* Return the mode. The mode is arbitrary. It can be the mode of the
207    channel or perhaps the mode of the client on the channel.  The protocol
208    dictates what the usage of the mode is in different circumstances. */
209
210 uint32 silc_channel_get_mode(SilcChannelPayload payload)
211 {
212   return payload->mode;
213 }
214
215 /******************************************************************************
216
217                           Channel Message Payload
218
219 ******************************************************************************/
220
221 /* Channel Message Payload structure. Contents of this structure is parsed
222    from SILC packets. */
223 struct SilcChannelMessagePayloadStruct {
224   uint16 flags;
225   uint16 data_len;
226   unsigned char *data;
227   unsigned char *mac;
228   unsigned char *iv;
229 };
230
231 /* Decrypts the channel message payload. */
232
233 int silc_channel_message_payload_decrypt(unsigned char *data,
234                                          size_t data_len,
235                                          SilcCipher cipher,
236                                          SilcHmac hmac)
237 {
238   uint32 iv_len, mac_len;
239   unsigned char *end, *mac, mac2[32];
240
241   /* Decrypt the channel message. First push the IV out of the packet.
242      The IV is used in the decryption process. Then decrypt the message.
243      After decyprtion, take the MAC from the decrypted packet, compute MAC
244      and compare the MACs.  If they match, the decryption was successfull
245      and we have the channel message ready to be displayed. */
246   end = data + data_len;
247
248   /* Push the IV out of the packet */
249   iv_len = silc_cipher_get_block_len(cipher);
250
251   /* Decrypt the channel message */
252   silc_cipher_decrypt(cipher, data, data, data_len - iv_len, (end - iv_len));
253
254   /* Take the MAC */
255   if (hmac) {
256     mac_len = silc_hmac_len(hmac);
257     mac = (end - iv_len - mac_len);
258
259     /* Check the MAC of the message */
260     SILC_LOG_DEBUG(("Checking channel message MACs"));
261     silc_hmac_make(hmac, data, (data_len - iv_len - mac_len), mac2, &mac_len);
262     if (memcmp(mac, mac2, mac_len)) {
263       SILC_LOG_DEBUG(("Channel message MACs does not match"));
264       return FALSE;
265     }
266     SILC_LOG_DEBUG(("MAC is Ok"));
267   }
268
269   return TRUE;
270 }
271
272 /* Parses channel message payload returning new channel payload structure.
273    This also decrypts it and checks the MAC. */
274
275 SilcChannelMessagePayload 
276 silc_channel_message_payload_parse(SilcBuffer buffer,
277                                    SilcCipher cipher,
278                                    SilcHmac hmac)
279 {
280   SilcChannelMessagePayload new;
281   int ret;
282   uint32 iv_len, mac_len;
283
284   SILC_LOG_DEBUG(("Parsing channel message payload"));
285
286   /* Decrypt the payload */
287   ret = silc_channel_message_payload_decrypt(buffer->data, buffer->len,
288                                      cipher, hmac);
289   if (ret == FALSE)
290     return NULL;
291
292   iv_len = silc_cipher_get_block_len(cipher);
293   mac_len = silc_hmac_len(hmac);
294
295   new = silc_calloc(1, sizeof(*new));
296
297   /* Parse the Channel Message Payload. Ignore the padding. */
298   ret = silc_buffer_unformat(buffer,
299                              SILC_STR_UI_SHORT(&new->flags),
300                              SILC_STR_UI16_NSTRING_ALLOC(&new->data, 
301                                                          &new->data_len),
302                              SILC_STR_UI16_NSTRING(NULL, NULL),
303                              SILC_STR_UI_XNSTRING(&new->mac, mac_len),
304                              SILC_STR_UI_XNSTRING(&new->iv, iv_len),
305                              SILC_STR_END);
306   if (ret == -1)
307     goto err;
308
309   if (new->data_len < 1 || new->data_len > buffer->len) {
310     SILC_LOG_ERROR(("Incorrect channel messaeg payload in packet, "
311                     "packet dropped"));
312     goto err;
313   }
314
315   return new;
316
317  err:
318   silc_channel_message_payload_free(new);
319   return NULL;
320 }
321
322 /* Encodes channel message payload into a buffer and returns it. This is used 
323    to add channel message payload into a packet. As the channel payload is
324    encrypted separately from other parts of the packet padding must
325    be applied to the payload. */
326
327 SilcBuffer silc_channel_message_payload_encode(uint16 flags,
328                                                uint16 data_len,
329                                                unsigned char *data,
330                                                uint16 iv_len,
331                                                unsigned char *iv,
332                                                SilcCipher cipher,
333                                                SilcHmac hmac)
334 {
335   int i;
336   SilcBuffer buffer;
337   uint32 len, pad_len, mac_len;
338   unsigned char pad[SILC_PACKET_MAX_PADLEN];
339   unsigned char mac[32];
340
341   SILC_LOG_DEBUG(("Encoding channel message payload"));
342
343   /* Calculate length of padding. IV is not included into the calculation
344      since it is not encrypted. */
345   mac_len = silc_hmac_len(hmac);
346   len = 6 + data_len + mac_len;
347   pad_len = SILC_PACKET_PADLEN((len + 2));
348
349   /* Allocate channel payload buffer */
350   len += pad_len + iv_len;
351   buffer = silc_buffer_alloc(len);
352
353   /* Generate padding */
354   for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
355
356   /* Encode the Channel Message Payload */
357   silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
358   silc_buffer_format(buffer, 
359                      SILC_STR_UI_SHORT(flags),
360                      SILC_STR_UI_SHORT(data_len),
361                      SILC_STR_UI_XNSTRING(data, data_len),
362                      SILC_STR_UI_SHORT(pad_len),
363                      SILC_STR_UI_XNSTRING(pad, pad_len),
364                      SILC_STR_END);
365
366   /* Compute the MAC of the channel message data */
367   silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
368
369   /* Put rest of the data to the payload */
370   silc_buffer_pull_tail(buffer, mac_len + iv_len);
371   silc_buffer_pull(buffer, 6 + data_len + pad_len);
372   silc_buffer_format(buffer, 
373                      SILC_STR_UI_XNSTRING(mac, mac_len),
374                      SILC_STR_UI_XNSTRING(iv, iv_len),
375                      SILC_STR_END);
376   silc_buffer_push(buffer, 6 + data_len + pad_len);
377
378   /* Encrypt payload of the packet. This is encrypted with the channel key. */
379   silc_cipher_encrypt(cipher, buffer->data, buffer->data, 
380                       buffer->len - iv_len, iv);
381
382   memset(pad, 0, sizeof(pad));
383   memset(mac, 0, sizeof(mac));
384
385   return buffer;
386 }
387
388 /* Free's Channel Message Payload */
389
390 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
391 {
392   if (payload->data) {
393     memset(payload->data, 0, payload->data_len);
394     silc_free(payload->data);
395   }
396   silc_free(payload);
397 }
398
399 /* Return flags */
400
401 uint16 
402 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
403 {
404   return payload->flags;
405 }
406
407 /* Return data */
408
409 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
410                                              uint32 *data_len)
411 {
412   if (data_len)
413     *data_len = payload->data_len;
414
415   return payload->data;
416 }
417
418 /* Return MAC. The caller knows the length of the MAC */
419
420 unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
421 {
422   return payload->mac;
423 }
424
425 /* Return IV. The caller knows the length of the IV */
426
427 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
428 {
429   return payload->iv;
430 }
431
432 /******************************************************************************
433
434                              Channel Key Payload
435
436 ******************************************************************************/
437
438 /* Channel Key Payload structrue. Channel keys are parsed from SILC
439    packets into this structure. */
440 struct SilcChannelKeyPayloadStruct {
441   uint16 id_len;
442   unsigned char *id;
443   uint16 cipher_len;
444   unsigned char *cipher;
445   uint16 key_len;
446   unsigned char *key;
447 };
448
449 /* Parses channel key payload returning new channel key payload structure */
450
451 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
452 {
453   SilcChannelKeyPayload new;
454   int ret;
455
456   SILC_LOG_DEBUG(("Parsing channel key payload"));
457
458   new = silc_calloc(1, sizeof(*new));
459
460   /* Parse the Channel Key Payload */
461   ret =
462     silc_buffer_unformat(buffer,
463                          SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
464                          SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
465                                                      &new->cipher_len),
466                          SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
467                          SILC_STR_END);
468   if (ret == -1)
469     goto err;
470
471   if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
472     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
473     goto err;
474   }
475
476   return new;
477
478  err:
479   if (new->id)
480     silc_free(new->id);
481   if (new->cipher)
482     silc_free(new->cipher);
483   if (new->key)
484     silc_free(new->key);
485   silc_free(new);
486   return NULL;
487 }
488
489 /* Encodes channel key payload into a buffer and returns it. This is used 
490    to add channel key payload into a packet. */
491
492 SilcBuffer silc_channel_key_payload_encode(uint16 id_len,
493                                            unsigned char *id,
494                                            uint16 cipher_len,
495                                            unsigned char *cipher,
496                                            uint16 key_len,
497                                            unsigned char *key)
498 {
499   SilcBuffer buffer;
500   uint32 len;
501
502   SILC_LOG_DEBUG(("Encoding channel key payload"));
503
504   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
505      2 + cipher */
506   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
507   buffer = silc_buffer_alloc(len);
508
509   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
510
511   /* Encode the Channel Payload */
512   silc_buffer_format(buffer, 
513                      SILC_STR_UI_SHORT(id_len),
514                      SILC_STR_UI_XNSTRING(id, id_len),
515                      SILC_STR_UI_SHORT(cipher_len),
516                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
517                      SILC_STR_UI_SHORT(key_len),
518                      SILC_STR_UI_XNSTRING(key, key_len),
519                      SILC_STR_END);
520
521   return buffer;
522 }
523
524 /* Free's Channel Key Payload */
525
526 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
527 {
528   if (payload) {
529     silc_free(payload->id);
530     silc_free(payload->cipher);
531     if (payload->key) {
532       memset(payload->key, 0, payload->key_len);
533       silc_free(payload->key);
534     }
535     silc_free(payload);
536   }
537 }
538
539 /* Return ID */
540
541 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
542                                        uint32 *id_len)
543 {
544   if (id_len)
545     *id_len = payload->id_len;
546
547   return payload->id;
548 }
549
550 /* Return cipher name */
551
552 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
553                                            uint32 *cipher_len)
554 {
555   if (cipher_len)
556     *cipher_len = payload->cipher_len;
557
558   return payload->cipher;
559 }
560
561 /* Return key */
562
563 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
564                                         uint32 *key_len)
565 {
566   if (key_len)
567     *key_len = payload->key_len;
568
569   return payload->key;
570 }