addition of silc.css
[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 /* Frees 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 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
222
223 /* Channel Message Payload structure. Contents of this structure is parsed
224    from SILC packets. */
225 struct SilcChannelMessagePayloadStruct {
226   SilcMessageFlags flags;
227   uint16 data_len;
228   unsigned char *data;
229   unsigned char *mac;
230   unsigned char *iv;
231 };
232
233 /* Decrypts the channel message payload. */
234
235 int silc_channel_message_payload_decrypt(unsigned char *data,
236                                          size_t data_len,
237                                          SilcCipher cipher,
238                                          SilcHmac hmac)
239 {
240   uint32 iv_len, mac_len;
241   unsigned char *end, *mac, mac2[32];
242
243   /* Decrypt the channel message. First push the IV out of the packet.
244      The IV is used in the decryption process. Then decrypt the message.
245      After decyprtion, take the MAC from the decrypted packet, compute MAC
246      and compare the MACs.  If they match, the decryption was successfull
247      and we have the channel message ready to be displayed. */
248   end = data + data_len;
249
250   /* Push the IV out of the packet */
251   iv_len = silc_cipher_get_block_len(cipher);
252
253   /* Decrypt the channel message */
254   silc_cipher_decrypt(cipher, data, data, data_len - iv_len, (end - iv_len));
255
256   /* Take the MAC */
257   if (hmac) {
258     mac_len = silc_hmac_len(hmac);
259     mac = (end - iv_len - mac_len);
260
261     /* Check the MAC of the message */
262     SILC_LOG_DEBUG(("Checking channel message MACs"));
263     silc_hmac_make(hmac, data, (data_len - iv_len - mac_len), mac2, &mac_len);
264     if (memcmp(mac, mac2, mac_len)) {
265       SILC_LOG_DEBUG(("Channel message MACs does not match"));
266       return FALSE;
267     }
268     SILC_LOG_DEBUG(("MAC is Ok"));
269   }
270
271   return TRUE;
272 }
273
274 /* Parses channel message payload returning new channel payload structure.
275    This also decrypts it and checks the MAC. */
276
277 SilcChannelMessagePayload 
278 silc_channel_message_payload_parse(SilcBuffer buffer,
279                                    SilcCipher cipher,
280                                    SilcHmac hmac)
281 {
282   SilcChannelMessagePayload new;
283   int ret;
284   uint32 iv_len, mac_len;
285
286   SILC_LOG_DEBUG(("Parsing channel message payload"));
287
288   /* Decrypt the payload */
289   ret = silc_channel_message_payload_decrypt(buffer->data, buffer->len,
290                                      cipher, hmac);
291   if (ret == FALSE)
292     return NULL;
293
294   iv_len = silc_cipher_get_block_len(cipher);
295   mac_len = silc_hmac_len(hmac);
296
297   new = silc_calloc(1, sizeof(*new));
298
299   /* Parse the Channel Message Payload. Ignore the padding. */
300   ret = silc_buffer_unformat(buffer,
301                              SILC_STR_UI_SHORT(&new->flags),
302                              SILC_STR_UI16_NSTRING_ALLOC(&new->data, 
303                                                          &new->data_len),
304                              SILC_STR_UI16_NSTRING(NULL, NULL),
305                              SILC_STR_UI_XNSTRING(&new->mac, mac_len),
306                              SILC_STR_UI_XNSTRING(&new->iv, iv_len),
307                              SILC_STR_END);
308   if (ret == -1)
309     goto err;
310
311   if (new->data_len < 1 || new->data_len > buffer->len) {
312     SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
313                     "packet dropped"));
314     goto err;
315   }
316
317   return new;
318
319  err:
320   silc_channel_message_payload_free(new);
321   return NULL;
322 }
323
324 /* Encodes channel message payload into a buffer and returns it. This is used 
325    to add channel message payload into a packet. As the channel payload is
326    encrypted separately from other parts of the packet padding must
327    be applied to the payload. */
328
329 SilcBuffer silc_channel_message_payload_encode(uint16 flags,
330                                                uint16 data_len,
331                                                unsigned char *data,
332                                                uint16 iv_len,
333                                                unsigned char *iv,
334                                                SilcCipher cipher,
335                                                SilcHmac hmac)
336 {
337   int i;
338   SilcBuffer buffer;
339   uint32 len, pad_len, mac_len;
340   unsigned char pad[16];
341   unsigned char mac[32];
342
343   SILC_LOG_DEBUG(("Encoding channel message payload"));
344
345   /* Calculate length of padding. IV is not included into the calculation
346      since it is not encrypted. */
347   mac_len = silc_hmac_len(hmac);
348   len = 6 + data_len + mac_len;
349   pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
350
351   /* Allocate channel payload buffer */
352   len += pad_len + iv_len;
353   buffer = silc_buffer_alloc(len);
354
355   /* Generate padding */
356   for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
357
358   /* Encode the Channel Message Payload */
359   silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
360   silc_buffer_format(buffer, 
361                      SILC_STR_UI_SHORT(flags),
362                      SILC_STR_UI_SHORT(data_len),
363                      SILC_STR_UI_XNSTRING(data, data_len),
364                      SILC_STR_UI_SHORT(pad_len),
365                      SILC_STR_UI_XNSTRING(pad, pad_len),
366                      SILC_STR_END);
367
368   /* Compute the MAC of the channel message data */
369   silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
370
371   /* Put rest of the data to the payload */
372   silc_buffer_pull_tail(buffer, mac_len + iv_len);
373   silc_buffer_pull(buffer, 6 + data_len + pad_len);
374   silc_buffer_format(buffer, 
375                      SILC_STR_UI_XNSTRING(mac, mac_len),
376                      SILC_STR_UI_XNSTRING(iv, iv_len),
377                      SILC_STR_END);
378   silc_buffer_push(buffer, 6 + data_len + pad_len);
379
380   /* Encrypt payload of the packet. This is encrypted with the channel key. */
381   silc_cipher_encrypt(cipher, buffer->data, buffer->data, 
382                       buffer->len - iv_len, iv);
383
384   memset(pad, 0, sizeof(pad));
385   memset(mac, 0, sizeof(mac));
386
387   return buffer;
388 }
389
390 /* Free's Channel Message Payload */
391
392 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
393 {
394   if (payload->data) {
395     memset(payload->data, 0, payload->data_len);
396     silc_free(payload->data);
397   }
398   silc_free(payload);
399 }
400
401 /* Return flags */
402
403 SilcMessageFlags
404 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
405 {
406   return payload->flags;
407 }
408
409 /* Return data */
410
411 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
412                                              uint32 *data_len)
413 {
414   if (data_len)
415     *data_len = payload->data_len;
416
417   return payload->data;
418 }
419
420 /* Return MAC. The caller knows the length of the MAC */
421
422 unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
423 {
424   return payload->mac;
425 }
426
427 /* Return IV. The caller knows the length of the IV */
428
429 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
430 {
431   return payload->iv;
432 }
433
434 /******************************************************************************
435
436                              Channel Key Payload
437
438 ******************************************************************************/
439
440 /* Channel Key Payload structrue. Channel keys are parsed from SILC
441    packets into this structure. */
442 struct SilcChannelKeyPayloadStruct {
443   uint16 id_len;
444   unsigned char *id;
445   uint16 cipher_len;
446   unsigned char *cipher;
447   uint16 key_len;
448   unsigned char *key;
449 };
450
451 /* Parses channel key payload returning new channel key payload structure */
452
453 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
454 {
455   SilcChannelKeyPayload new;
456   int ret;
457
458   SILC_LOG_DEBUG(("Parsing channel key payload"));
459
460   new = silc_calloc(1, sizeof(*new));
461
462   /* Parse the Channel Key Payload */
463   ret =
464     silc_buffer_unformat(buffer,
465                          SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
466                          SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
467                                                      &new->cipher_len),
468                          SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
469                          SILC_STR_END);
470   if (ret == -1)
471     goto err;
472
473   if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
474     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
475     goto err;
476   }
477
478   return new;
479
480  err:
481   if (new->id)
482     silc_free(new->id);
483   if (new->cipher)
484     silc_free(new->cipher);
485   if (new->key)
486     silc_free(new->key);
487   silc_free(new);
488   return NULL;
489 }
490
491 /* Encodes channel key payload into a buffer and returns it. This is used 
492    to add channel key payload into a packet. */
493
494 SilcBuffer silc_channel_key_payload_encode(uint16 id_len,
495                                            unsigned char *id,
496                                            uint16 cipher_len,
497                                            unsigned char *cipher,
498                                            uint16 key_len,
499                                            unsigned char *key)
500 {
501   SilcBuffer buffer;
502   uint32 len;
503
504   SILC_LOG_DEBUG(("Encoding channel key payload"));
505
506   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
507      2 + cipher */
508   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
509   buffer = silc_buffer_alloc(len);
510
511   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
512
513   /* Encode the Channel Payload */
514   silc_buffer_format(buffer, 
515                      SILC_STR_UI_SHORT(id_len),
516                      SILC_STR_UI_XNSTRING(id, id_len),
517                      SILC_STR_UI_SHORT(cipher_len),
518                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
519                      SILC_STR_UI_SHORT(key_len),
520                      SILC_STR_UI_XNSTRING(key, key_len),
521                      SILC_STR_END);
522
523   return buffer;
524 }
525
526 /* Frees Channel Key Payload */
527
528 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
529 {
530   if (payload) {
531     silc_free(payload->id);
532     silc_free(payload->cipher);
533     if (payload->key) {
534       memset(payload->key, 0, payload->key_len);
535       silc_free(payload->key);
536     }
537     silc_free(payload);
538   }
539 }
540
541 /* Return ID */
542
543 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
544                                        uint32 *id_len)
545 {
546   if (id_len)
547     *id_len = payload->id_len;
548
549   return payload->id;
550 }
551
552 /* Return cipher name */
553
554 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
555                                            uint32 *cipher_len)
556 {
557   if (cipher_len)
558     *cipher_len = payload->cipher_len;
559
560   return payload->cipher;
561 }
562
563 /* Return key */
564
565 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
566                                         uint32 *key_len)
567 {
568   if (key_len)
569     *key_len = payload->key_len;
570
571   return payload->key;
572 }