updates.
[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   unsigned short name_len;
37   unsigned char *channel_name;
38   unsigned short id_len;
39   unsigned char *channel_id;
40   unsigned int 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                                        unsigned short channel_name_len,
127                                        unsigned char *channel_id,
128                                        unsigned int channel_id_len,
129                                        unsigned int 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                                      unsigned int *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                                    unsigned int *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 unsigned int 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   unsigned short flags;
225   unsigned short 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   unsigned int 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   unsigned int 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(unsigned short flags,
328                                                unsigned short data_len,
329                                                unsigned char *data,
330                                                unsigned short iv_len,
331                                                unsigned char *iv,
332                                                SilcCipher cipher,
333                                                SilcHmac hmac)
334 {
335   int i;
336   SilcBuffer buffer;
337   unsigned int 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 data */
400
401 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
402                                              unsigned int *data_len)
403 {
404   if (data_len)
405     *data_len = payload->data_len;
406
407   return payload->data;
408 }
409
410 /* Return MAC. The caller knows the length of the MAC */
411
412 unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
413 {
414   return payload->mac;
415 }
416
417 /* Return IV. The caller knows the length of the IV */
418
419 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
420 {
421   return payload->iv;
422 }
423
424 /******************************************************************************
425
426                              Channel Key Payload
427
428 ******************************************************************************/
429
430 /* Channel Key Payload structrue. Channel keys are parsed from SILC
431    packets into this structure. */
432 struct SilcChannelKeyPayloadStruct {
433   unsigned short id_len;
434   unsigned char *id;
435   unsigned short cipher_len;
436   unsigned char *cipher;
437   unsigned short key_len;
438   unsigned char *key;
439 };
440
441 /* Parses channel key payload returning new channel key payload structure */
442
443 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
444 {
445   SilcChannelKeyPayload new;
446   int ret;
447
448   SILC_LOG_DEBUG(("Parsing channel key payload"));
449
450   new = silc_calloc(1, sizeof(*new));
451
452   /* Parse the Channel Key Payload */
453   ret =
454     silc_buffer_unformat(buffer,
455                          SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
456                          SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
457                                                      &new->cipher_len),
458                          SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
459                          SILC_STR_END);
460   if (ret == -1)
461     goto err;
462
463   if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
464     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
465     goto err;
466   }
467
468   return new;
469
470  err:
471   if (new->id)
472     silc_free(new->id);
473   if (new->cipher)
474     silc_free(new->cipher);
475   if (new->key)
476     silc_free(new->key);
477   silc_free(new);
478   return NULL;
479 }
480
481 /* Encodes channel key payload into a buffer and returns it. This is used 
482    to add channel key payload into a packet. */
483
484 SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
485                                            unsigned char *id,
486                                            unsigned short cipher_len,
487                                            unsigned char *cipher,
488                                            unsigned short key_len,
489                                            unsigned char *key)
490 {
491   SilcBuffer buffer;
492   unsigned int len;
493
494   SILC_LOG_DEBUG(("Encoding channel key payload"));
495
496   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
497      2 + cipher */
498   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
499   buffer = silc_buffer_alloc(len);
500
501   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
502
503   /* Encode the Channel Payload */
504   silc_buffer_format(buffer, 
505                      SILC_STR_UI_SHORT(id_len),
506                      SILC_STR_UI_XNSTRING(id, id_len),
507                      SILC_STR_UI_SHORT(cipher_len),
508                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
509                      SILC_STR_UI_SHORT(key_len),
510                      SILC_STR_UI_XNSTRING(key, key_len),
511                      SILC_STR_END);
512
513   return buffer;
514 }
515
516 /* Free's Channel Key Payload */
517
518 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
519 {
520   if (payload) {
521     if (payload->id)
522       silc_free(payload->id);
523     if (payload->cipher)
524       silc_free(payload->cipher);
525     if (payload->key) {
526       memset(payload->key, 0, payload->key_len);
527       silc_free(payload->key);
528     }
529     silc_free(payload);
530   }
531 }
532
533 /* Return ID */
534
535 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
536                                        unsigned int *id_len)
537 {
538   if (id_len)
539     *id_len = payload->id_len;
540
541   return payload->id;
542 }
543
544 /* Return cipher name */
545
546 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
547                                            unsigned int *cipher_len)
548 {
549   if (cipher_len)
550     *cipher_len = payload->cipher_len;
551
552   return payload->cipher;
553 }
554
555 /* Return key */
556
557 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
558                                         unsigned int *key_len)
559 {
560   if (key_len)
561     *key_len = payload->key_len;
562
563   return payload->key;
564 }