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   SilcUInt16 name_len;
37   unsigned char *channel_name;
38   SilcUInt16 id_len;
39   unsigned char *channel_id;
40   SilcUInt32 mode;
41 };
42
43 /* Parses channel payload returning new channel payload structure. */
44
45 SilcChannelPayload silc_channel_payload_parse(const unsigned char *payload,
46                                               SilcUInt32 payload_len)
47 {
48   SilcBufferStruct buffer;
49   SilcChannelPayload newp;
50   int ret;
51
52   SILC_LOG_DEBUG(("Parsing channel payload"));
53
54   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
55   newp = silc_calloc(1, sizeof(*newp));
56   if (!newp)
57     return NULL;
58
59   /* Parse the Channel Payload. Ignore the padding. */
60   ret = silc_buffer_unformat(&buffer,
61                              SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name, 
62                                                          &newp->name_len),
63                              SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id, 
64                                                          &newp->id_len),
65                              SILC_STR_UI_INT(&newp->mode),
66                              SILC_STR_END);
67   if (ret == -1)
68     goto err;
69
70   if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
71       (newp->id_len < 1 || newp->id_len > buffer.len)) {
72     SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
73     goto err;
74   }
75
76   return newp;
77
78  err:
79   silc_channel_payload_free(newp);
80   return NULL;
81 }
82
83 /* Parses list of channel payloads returning list of payloads. */
84
85 SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
86                                           SilcUInt32 payload_len)
87 {
88   SilcBufferStruct buffer;
89   SilcDList list;
90   SilcChannelPayload newp;
91   int len, ret;
92
93   SILC_LOG_DEBUG(("Parsing channel payload list"));
94
95   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
96   list = silc_dlist_init();
97
98   while (buffer.len) {
99     newp = silc_calloc(1, sizeof(*newp));
100     if (!newp)
101       goto err;
102     ret = silc_buffer_unformat(&buffer,
103                                SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name, 
104                                                            &newp->name_len),
105                                SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id, 
106                                                            &newp->id_len),
107                                SILC_STR_UI_INT(&newp->mode),
108                                SILC_STR_END);
109     if (ret == -1)
110       goto err;
111
112     if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
113         (newp->id_len < 1 || newp->id_len > buffer.len)) {
114       SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
115       goto err;
116     }
117
118     len = 2 + newp->name_len + 2 + newp->id_len + 4;
119     if (buffer.len < len)
120       break;
121     silc_buffer_pull(&buffer, len);
122
123     silc_dlist_add(list, newp);
124   }
125   
126   return list;
127
128  err:
129   silc_channel_payload_list_free(list);
130   return NULL;
131 }
132
133 /* Encode new channel payload and returns it as buffer. */
134
135 SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name,
136                                        SilcUInt16 channel_name_len,
137                                        const unsigned char *channel_id,
138                                        SilcUInt32 channel_id_len,
139                                        SilcUInt32 mode)
140 {
141   SilcBuffer buffer;
142
143   SILC_LOG_DEBUG(("Encoding message payload"));
144
145   buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 + 
146                                   channel_id_len + 4);
147   if (!buffer)
148     return NULL;
149
150   /* Encode the Channel Payload */
151   silc_buffer_format(buffer, 
152                      SILC_STR_UI_SHORT(channel_name_len),
153                      SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
154                      SILC_STR_UI_SHORT(channel_id_len),
155                      SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
156                      SILC_STR_UI_INT(mode),
157                      SILC_STR_END);
158
159   return buffer;
160 }
161
162 /* Frees Channel Payload */
163
164 void silc_channel_payload_free(SilcChannelPayload payload)
165 {
166   silc_free(payload->channel_name);
167   silc_free(payload->channel_id);
168   silc_free(payload);
169 }
170
171 /* Free's list of Channel Payloads */
172
173 void silc_channel_payload_list_free(SilcDList list)
174 {
175   SilcChannelPayload entry;
176
177   silc_dlist_start(list);
178   while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
179     silc_free(entry->channel_name);
180     silc_free(entry->channel_id);
181     silc_dlist_del(list, entry);
182     silc_free(entry);
183   }
184
185   silc_dlist_uninit(list);
186 }
187
188 /* Return the channel name */
189
190 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
191                                      SilcUInt32 *channel_name_len)
192 {
193   if (channel_name_len)
194     *channel_name_len = payload->name_len;
195
196   return payload->channel_name;
197 }
198
199 /* Return the channel ID */
200
201 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
202                                    SilcUInt32 *channel_id_len)
203 {
204   if (channel_id_len)
205     *channel_id_len = payload->id_len;
206
207   return payload->channel_id;
208 }
209
210 /* Return the channel ID as parsed ID. */
211
212 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
213 {
214   return silc_id_str2id(payload->channel_id, payload->id_len,
215                         SILC_ID_CHANNEL);
216 }
217
218 /* Return the mode. The mode is arbitrary. It can be the mode of the
219    channel or perhaps the mode of the client on the channel.  The protocol
220    dictates what the usage of the mode is in different circumstances. */
221
222 SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload)
223 {
224   return payload->mode;
225 }
226
227 /******************************************************************************
228
229                           Channel Message Payload
230
231 ******************************************************************************/
232
233 /* Calculates padding length for message payload */
234 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
235
236 /* Header length plus maximum padding length */
237 #define SILC_CHANNEL_MESSAGE_HLEN 6 + 16
238
239 /* Returns the data length that fits to the packet.  If data length is too
240    big it will be truncated to fit to the payload. */
241 #define SILC_CHANNEL_MESSAGE_DATALEN(data_len, header_len)              \
242   ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) >                \
243    SILC_PACKET_MAX_LEN ?                                                \
244    data_len - ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) -    \
245                SILC_PACKET_MAX_LEN) : data_len)
246
247 /* Channel Message Payload structure. Contents of this structure is parsed
248    from SILC packets. */
249 struct SilcChannelMessagePayloadStruct {
250   SilcMessageFlags flags;
251   SilcUInt16 data_len;
252   unsigned char *data;
253   SilcUInt16 pad_len;
254   unsigned char *pad;
255   unsigned char *mac;
256   unsigned char *iv;
257 };
258
259 /* Decrypts the channel message payload. First push the IV out of the
260    packet. The IV is used in the decryption process. Then decrypt the
261    message. After decyprtion, take the MAC from the decrypted packet, 
262    compute MAC and compare the MACs.  If they match, the decryption was
263    successful and we have the channel message ready to be displayed. */
264
265 bool silc_channel_message_payload_decrypt(unsigned char *data,
266                                           size_t data_len,
267                                           SilcCipher cipher,
268                                           SilcHmac hmac)
269 {
270   SilcUInt32 iv_len, mac_len;
271   unsigned char *end, *mac, mac2[32];
272   unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
273
274   /* Push the IV out of the packet, and copy the IV since we do not want
275      to modify the original data buffer. */
276   end = data + data_len;
277   iv_len = silc_cipher_get_block_len(cipher);
278   memcpy(iv, end - iv_len, iv_len);
279
280   /* Allocate destination decryption buffer since we do not want to modify
281      the original data buffer, since we might want to call this function 
282      many times for same payload. */
283   if (hmac) {
284     dst = silc_calloc(data_len - iv_len, sizeof(*dst));
285     if (!dst)
286       return FALSE;
287   } else {
288     dst = data;
289   }
290
291   /* Decrypt the channel message */
292   silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
293
294   if (hmac) {
295     /* Take the MAC */
296     end = dst + (data_len - iv_len);
297     mac_len = silc_hmac_len(hmac);
298     mac = (end - mac_len);
299
300     /* Check the MAC of the message */
301     SILC_LOG_DEBUG(("Checking channel message MACs"));
302     silc_hmac_init(hmac);
303     silc_hmac_update(hmac, dst, (data_len - iv_len - mac_len));
304     silc_hmac_update(hmac, data + (data_len - iv_len), iv_len);
305     silc_hmac_final(hmac, mac2, &mac_len);
306     if (memcmp(mac, mac2, mac_len)) {
307       SILC_LOG_DEBUG(("Channel message MACs does not match"));
308       silc_free(dst);
309       return FALSE;
310     }
311     SILC_LOG_DEBUG(("MAC is Ok"));
312
313     /* Now copy the decrypted data into the buffer since it is verified
314        it decrypted correctly. */
315     memcpy(data, dst, data_len - iv_len);
316     memset(dst, 0, data_len - iv_len);
317     silc_free(dst);
318   }
319
320   return TRUE;
321 }
322
323 /* Parses channel message payload returning new channel payload structure.
324    This also decrypts it and checks the MAC. */
325
326 SilcChannelMessagePayload 
327 silc_channel_message_payload_parse(unsigned char *payload,
328                                    SilcUInt32 payload_len,
329                                    SilcCipher cipher,
330                                    SilcHmac hmac)
331 {
332   SilcBufferStruct buffer;
333   SilcChannelMessagePayload newp;
334   int ret;
335   SilcUInt32 iv_len, mac_len;
336
337   SILC_LOG_DEBUG(("Parsing channel message payload"));
338
339   silc_buffer_set(&buffer, payload, payload_len);
340
341   /* Decrypt the payload */
342   ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
343                                              cipher, hmac);
344   if (ret == FALSE)
345     return NULL;
346
347   iv_len = silc_cipher_get_block_len(cipher);
348   mac_len = silc_hmac_len(hmac);
349
350   newp = silc_calloc(1, sizeof(*newp));
351   if (!newp)
352     return NULL;
353
354   /* Parse the Channel Message Payload. */
355   ret = silc_buffer_unformat(&buffer,
356                              SILC_STR_UI_SHORT(&newp->flags),
357                              SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
358                                                          &newp->data_len),
359                              SILC_STR_UI16_NSTRING_ALLOC(&newp->pad, 
360                                                          &newp->pad_len),
361                              SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
362                              SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
363                              SILC_STR_END);
364   if (ret == -1)
365     goto err;
366
367   if (newp->data_len > buffer.len) {
368     SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
369                     "packet dropped"));
370     goto err;
371   }
372
373   return newp;
374
375  err:
376   silc_channel_message_payload_free(newp);
377   return NULL;
378 }
379
380 /* This function is used to encrypt the Channel Messsage Payload which is
381    the `data' and `data_len'.  This is used internally by the Channel Message
382    Payload encoding routines but application may call this too if needed. 
383    The `data_len' is the data lenght which is used to create MAC out of.
384    The `true_len' is the true length of `data' message payload and is used
385    assemble rest of the packet after MAC creation. The `true_len' length
386    packet will then be encrypted. */
387
388 bool silc_channel_message_payload_encrypt(unsigned char *data,
389                                           SilcUInt32 data_len,
390                                           SilcUInt32 true_len,
391                                           unsigned char *iv,
392                                           SilcUInt32 iv_len,
393                                           SilcCipher cipher,
394                                           SilcHmac hmac)
395 {
396   unsigned char mac[32];
397   SilcUInt32 mac_len;
398   SilcBufferStruct buf;
399
400   /* Compute the MAC of the channel message data */
401   silc_hmac_init(hmac);
402   silc_hmac_update(hmac, data, data_len);
403   silc_hmac_update(hmac, iv, iv_len);
404   silc_hmac_final(hmac, mac, &mac_len);
405
406   /* Put rest of the data to the payload */
407   silc_buffer_set(&buf, data, true_len);
408   silc_buffer_pull(&buf, data_len);
409   silc_buffer_format(&buf, 
410                      SILC_STR_UI_XNSTRING(mac, mac_len),
411                      SILC_STR_UI_XNSTRING(iv, iv_len),
412                      SILC_STR_END);
413
414   /* Encrypt payload of the packet. This is encrypted with the channel key. */
415   silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
416
417   memset(mac, 0, sizeof(mac));
418   return TRUE;
419 }
420
421 /* Encodes channel message payload into a buffer and returns it. This is used 
422    to add channel message payload into a packet. As the channel payload is
423    encrypted separately from other parts of the packet padding must
424    be applied to the payload. */
425
426 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
427                                                SilcUInt16 data_len,
428                                                const unsigned char *data,
429                                                SilcUInt16 iv_len,
430                                                unsigned char *iv,
431                                                SilcCipher cipher,
432                                                SilcHmac hmac,
433                                                SilcRng rng)
434 {
435   int i;
436   SilcBuffer buffer;
437   SilcUInt32 len, pad_len, mac_len;
438   unsigned char pad[16];
439
440   SILC_LOG_DEBUG(("Encoding channel message payload"));
441
442   /* Calculate length of padding. IV is not included into the calculation
443      since it is not encrypted. */
444   mac_len = silc_hmac_len(hmac);
445   data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
446   len = 6 + data_len + mac_len;
447   pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
448
449   /* Allocate channel payload buffer */
450   len += pad_len + iv_len;
451   buffer = silc_buffer_alloc(len);
452   if (!buffer)
453     return NULL;
454
455   /* Generate padding */
456   if (rng) {
457     for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
458   } else {
459     for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
460   }
461
462   /* Encode the Channel Message Payload */
463   silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
464   silc_buffer_format(buffer, 
465                      SILC_STR_UI_SHORT(flags),
466                      SILC_STR_UI_SHORT(data_len),
467                      SILC_STR_UI_XNSTRING(data, data_len),
468                      SILC_STR_UI_SHORT(pad_len),
469                      SILC_STR_UI_XNSTRING(pad, pad_len),
470                      SILC_STR_END);
471
472   memset(pad, 0, sizeof(pad));
473
474   if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
475                                             buffer->truelen, iv, iv_len,
476                                             cipher, hmac)) {
477     silc_buffer_free(buffer);
478     return NULL;
479   }
480
481   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
482
483   return buffer;
484 }
485
486 /* Free's Channel Message Payload */
487
488 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
489 {
490   if (payload->data) {
491     memset(payload->data, 0, payload->data_len);
492     silc_free(payload->data);
493   }
494   silc_free(payload);
495 }
496
497 /* Return flags */
498
499 SilcMessageFlags
500 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
501 {
502   return payload->flags;
503 }
504
505 /* Return data */
506
507 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
508                                              SilcUInt32 *data_len)
509 {
510   if (data_len)
511     *data_len = payload->data_len;
512
513   return payload->data;
514 }
515
516 /* Return MAC. The caller knows the length of the MAC */
517
518 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
519 {
520   return payload->mac;
521 }
522
523 /* Return IV. The caller knows the length of the IV */
524
525 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
526 {
527   return payload->iv;
528 }
529
530 /******************************************************************************
531
532                              Channel Key Payload
533
534 ******************************************************************************/
535
536 /* Channel Key Payload structrue. Channel keys are parsed from SILC
537    packets into this structure. */
538 struct SilcChannelKeyPayloadStruct {
539   SilcUInt16 id_len;
540   unsigned char *id;
541   SilcUInt16 cipher_len;
542   unsigned char *cipher;
543   SilcUInt16 key_len;
544   unsigned char *key;
545 };
546
547 /* Parses channel key payload returning new channel key payload structure */
548
549 SilcChannelKeyPayload 
550 silc_channel_key_payload_parse(const unsigned char *payload,
551                                SilcUInt32 payload_len)
552 {
553   SilcBufferStruct buffer;
554   SilcChannelKeyPayload newp;
555   int ret;
556
557   SILC_LOG_DEBUG(("Parsing channel key payload"));
558
559   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
560   newp = silc_calloc(1, sizeof(*newp));
561   if (!newp)
562     return NULL;
563
564   /* Parse the Channel Key Payload */
565   ret =
566     silc_buffer_unformat(&buffer,
567                          SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
568                          SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher, 
569                                                      &newp->cipher_len),
570                          SILC_STR_UI16_NSTRING_ALLOC(&newp->key, 
571                                                      &newp->key_len),
572                          SILC_STR_END);
573   if (ret == -1)
574     goto err;
575
576   if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
577     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
578     goto err;
579   }
580
581   return newp;
582
583  err:
584   if (newp->id)
585     silc_free(newp->id);
586   if (newp->cipher)
587     silc_free(newp->cipher);
588   if (newp->key)
589     silc_free(newp->key);
590   silc_free(newp);
591   return NULL;
592 }
593
594 /* Encodes channel key payload into a buffer and returns it. This is used 
595    to add channel key payload into a packet. */
596
597 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
598                                            const unsigned char *id,
599                                            SilcUInt16 cipher_len,
600                                            const unsigned char *cipher,
601                                            SilcUInt16 key_len,
602                                            const unsigned char *key)
603 {
604   SilcBuffer buffer;
605   SilcUInt32 len;
606
607   SILC_LOG_DEBUG(("Encoding channel key payload"));
608
609   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
610      2 + cipher */
611   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
612   buffer = silc_buffer_alloc_size(len);
613   if (!buffer)
614     return NULL;
615
616   /* Encode the Channel Payload */
617   silc_buffer_format(buffer, 
618                      SILC_STR_UI_SHORT(id_len),
619                      SILC_STR_UI_XNSTRING(id, id_len),
620                      SILC_STR_UI_SHORT(cipher_len),
621                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
622                      SILC_STR_UI_SHORT(key_len),
623                      SILC_STR_UI_XNSTRING(key, key_len),
624                      SILC_STR_END);
625
626   return buffer;
627 }
628
629 /* Frees Channel Key Payload */
630
631 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
632 {
633   if (payload) {
634     silc_free(payload->id);
635     silc_free(payload->cipher);
636     if (payload->key) {
637       memset(payload->key, 0, payload->key_len);
638       silc_free(payload->key);
639     }
640     silc_free(payload);
641   }
642 }
643
644 /* Return ID */
645
646 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
647                                        SilcUInt32 *id_len)
648 {
649   if (id_len)
650     *id_len = payload->id_len;
651
652   return payload->id;
653 }
654
655 /* Return cipher name */
656
657 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
658                                            SilcUInt32 *cipher_len)
659 {
660   if (cipher_len)
661     *cipher_len = payload->cipher_len;
662
663   return payload->cipher;
664 }
665
666 /* Return key */
667
668 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
669                                         SilcUInt32 *key_len)
670 {
671   if (key_len)
672     *key_len = payload->key_len;
673
674   return payload->key;
675 }