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   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 /* Channel Message Payload structure. Contents of this structure is parsed
222    from SILC packets. */
223 struct SilcChannelMessagePayloadStruct {
224   SilcMessageFlags 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 message 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, block_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   block_len = silc_cipher_get_block_len(cipher);
347   len = 6 + data_len + mac_len;
348   pad_len = SILC_PACKET_PADLEN(len, block_len);
349
350   /* Allocate channel payload buffer */
351   len += pad_len + iv_len;
352   buffer = silc_buffer_alloc(len);
353
354   /* Generate padding */
355   for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
356
357   /* Encode the Channel Message Payload */
358   silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
359   silc_buffer_format(buffer, 
360                      SILC_STR_UI_SHORT(flags),
361                      SILC_STR_UI_SHORT(data_len),
362                      SILC_STR_UI_XNSTRING(data, data_len),
363                      SILC_STR_UI_SHORT(pad_len),
364                      SILC_STR_UI_XNSTRING(pad, pad_len),
365                      SILC_STR_END);
366
367   /* Compute the MAC of the channel message data */
368   silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
369
370   /* Put rest of the data to the payload */
371   silc_buffer_pull_tail(buffer, mac_len + iv_len);
372   silc_buffer_pull(buffer, 6 + data_len + pad_len);
373   silc_buffer_format(buffer, 
374                      SILC_STR_UI_XNSTRING(mac, mac_len),
375                      SILC_STR_UI_XNSTRING(iv, iv_len),
376                      SILC_STR_END);
377   silc_buffer_push(buffer, 6 + data_len + pad_len);
378
379   /* Encrypt payload of the packet. This is encrypted with the channel key. */
380   silc_cipher_encrypt(cipher, buffer->data, buffer->data, 
381                       buffer->len - iv_len, iv);
382
383   memset(pad, 0, sizeof(pad));
384   memset(mac, 0, sizeof(mac));
385
386   return buffer;
387 }
388
389 /* Free's Channel Message Payload */
390
391 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
392 {
393   if (payload->data) {
394     memset(payload->data, 0, payload->data_len);
395     silc_free(payload->data);
396   }
397   silc_free(payload);
398 }
399
400 /* Return flags */
401
402 SilcMessageFlags
403 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
404 {
405   return payload->flags;
406 }
407
408 /* Return data */
409
410 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
411                                              uint32 *data_len)
412 {
413   if (data_len)
414     *data_len = payload->data_len;
415
416   return payload->data;
417 }
418
419 /* Return MAC. The caller knows the length of the MAC */
420
421 unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
422 {
423   return payload->mac;
424 }
425
426 /* Return IV. The caller knows the length of the IV */
427
428 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
429 {
430   return payload->iv;
431 }
432
433 /******************************************************************************
434
435                              Channel Key Payload
436
437 ******************************************************************************/
438
439 /* Channel Key Payload structrue. Channel keys are parsed from SILC
440    packets into this structure. */
441 struct SilcChannelKeyPayloadStruct {
442   uint16 id_len;
443   unsigned char *id;
444   uint16 cipher_len;
445   unsigned char *cipher;
446   uint16 key_len;
447   unsigned char *key;
448 };
449
450 /* Parses channel key payload returning new channel key payload structure */
451
452 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
453 {
454   SilcChannelKeyPayload new;
455   int ret;
456
457   SILC_LOG_DEBUG(("Parsing channel key payload"));
458
459   new = silc_calloc(1, sizeof(*new));
460
461   /* Parse the Channel Key Payload */
462   ret =
463     silc_buffer_unformat(buffer,
464                          SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
465                          SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
466                                                      &new->cipher_len),
467                          SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
468                          SILC_STR_END);
469   if (ret == -1)
470     goto err;
471
472   if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
473     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
474     goto err;
475   }
476
477   return new;
478
479  err:
480   if (new->id)
481     silc_free(new->id);
482   if (new->cipher)
483     silc_free(new->cipher);
484   if (new->key)
485     silc_free(new->key);
486   silc_free(new);
487   return NULL;
488 }
489
490 /* Encodes channel key payload into a buffer and returns it. This is used 
491    to add channel key payload into a packet. */
492
493 SilcBuffer silc_channel_key_payload_encode(uint16 id_len,
494                                            unsigned char *id,
495                                            uint16 cipher_len,
496                                            unsigned char *cipher,
497                                            uint16 key_len,
498                                            unsigned char *key)
499 {
500   SilcBuffer buffer;
501   uint32 len;
502
503   SILC_LOG_DEBUG(("Encoding channel key payload"));
504
505   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
506      2 + cipher */
507   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
508   buffer = silc_buffer_alloc(len);
509
510   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
511
512   /* Encode the Channel Payload */
513   silc_buffer_format(buffer, 
514                      SILC_STR_UI_SHORT(id_len),
515                      SILC_STR_UI_XNSTRING(id, id_len),
516                      SILC_STR_UI_SHORT(cipher_len),
517                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
518                      SILC_STR_UI_SHORT(key_len),
519                      SILC_STR_UI_XNSTRING(key, key_len),
520                      SILC_STR_END);
521
522   return buffer;
523 }
524
525 /* Frees Channel Key Payload */
526
527 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
528 {
529   if (payload) {
530     silc_free(payload->id);
531     silc_free(payload->cipher);
532     if (payload->key) {
533       memset(payload->key, 0, payload->key_len);
534       silc_free(payload->key);
535     }
536     silc_free(payload);
537   }
538 }
539
540 /* Return ID */
541
542 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
543                                        uint32 *id_len)
544 {
545   if (id_len)
546     *id_len = payload->id_len;
547
548   return payload->id;
549 }
550
551 /* Return cipher name */
552
553 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
554                                            uint32 *cipher_len)
555 {
556   if (cipher_len)
557     *cipher_len = payload->cipher_len;
558
559   return payload->cipher;
560 }
561
562 /* Return key */
563
564 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
565                                         uint32 *key_len)
566 {
567   if (key_len)
568     *key_len = payload->key_len;
569
570   return payload->key;
571 }