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_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
303     if (memcmp(mac, mac2, mac_len)) {
304       SILC_LOG_DEBUG(("Channel message MACs does not match"));
305       silc_free(dst);
306       return FALSE;
307     }
308     SILC_LOG_DEBUG(("MAC is Ok"));
309
310     /* Now copy the decrypted data into the buffer since it is verified
311        it decrypted correctly. */
312     memcpy(data, dst, data_len - iv_len);
313     memset(dst, 0, data_len - iv_len);
314     silc_free(dst);
315   }
316
317   return TRUE;
318 }
319
320 /* Parses channel message payload returning new channel payload structure.
321    This also decrypts it and checks the MAC. */
322
323 SilcChannelMessagePayload 
324 silc_channel_message_payload_parse(unsigned char *payload,
325                                    SilcUInt32 payload_len,
326                                    SilcCipher cipher,
327                                    SilcHmac hmac)
328 {
329   SilcBufferStruct buffer;
330   SilcChannelMessagePayload newp;
331   int ret;
332   SilcUInt32 iv_len, mac_len;
333
334   SILC_LOG_DEBUG(("Parsing channel message payload"));
335
336   silc_buffer_set(&buffer, payload, payload_len);
337
338   /* Decrypt the payload */
339   ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
340                                              cipher, hmac);
341   if (ret == FALSE)
342     return NULL;
343
344   iv_len = silc_cipher_get_block_len(cipher);
345   mac_len = silc_hmac_len(hmac);
346
347   newp = silc_calloc(1, sizeof(*newp));
348   if (!newp)
349     return NULL;
350
351   /* Parse the Channel Message Payload. */
352   ret = silc_buffer_unformat(&buffer,
353                              SILC_STR_UI_SHORT(&newp->flags),
354                              SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
355                                                          &newp->data_len),
356                              SILC_STR_UI16_NSTRING_ALLOC(&newp->pad, 
357                                                          &newp->pad_len),
358                              SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
359                              SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
360                              SILC_STR_END);
361   if (ret == -1)
362     goto err;
363
364   if (newp->data_len > buffer.len) {
365     SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
366                     "packet dropped"));
367     goto err;
368   }
369
370   return newp;
371
372  err:
373   silc_channel_message_payload_free(newp);
374   return NULL;
375 }
376
377 /* This function is used to encrypt the Channel Messsage Payload which is
378    the `data' and `data_len'.  This is used internally by the Channel Message
379    Payload encoding routines but application may call this too if needed. 
380    The `data_len' is the data lenght which is used to create MAC out of.
381    The `true_len' is the true length of `data' message payload and is used
382    assemble rest of the packet after MAC creation. The `true_len' length
383    packet will then be encrypted. */
384
385 bool silc_channel_message_payload_encrypt(unsigned char *data,
386                                           SilcUInt32 data_len,
387                                           SilcUInt32 true_len,
388                                           unsigned char *iv,
389                                           SilcUInt32 iv_len,
390                                           SilcCipher cipher,
391                                           SilcHmac hmac)
392 {
393   unsigned char mac[32];
394   SilcUInt32 mac_len;
395   SilcBufferStruct buf;
396
397   /* Compute the MAC of the channel message data */
398   silc_hmac_make(hmac, data, data_len, mac, &mac_len);
399
400   /* Put rest of the data to the payload */
401   silc_buffer_set(&buf, data, true_len);
402   silc_buffer_pull(&buf, data_len);
403   silc_buffer_format(&buf, 
404                      SILC_STR_UI_XNSTRING(mac, mac_len),
405                      SILC_STR_UI_XNSTRING(iv, iv_len),
406                      SILC_STR_END);
407
408   /* Encrypt payload of the packet. This is encrypted with the channel key. */
409   silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
410
411   memset(mac, 0, sizeof(mac));
412   return TRUE;
413 }
414
415 /* Encodes channel message payload into a buffer and returns it. This is used 
416    to add channel message payload into a packet. As the channel payload is
417    encrypted separately from other parts of the packet padding must
418    be applied to the payload. */
419
420 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
421                                                SilcUInt16 data_len,
422                                                const unsigned char *data,
423                                                SilcUInt16 iv_len,
424                                                unsigned char *iv,
425                                                SilcCipher cipher,
426                                                SilcHmac hmac,
427                                                SilcRng rng)
428 {
429   int i;
430   SilcBuffer buffer;
431   SilcUInt32 len, pad_len, mac_len;
432   unsigned char pad[16];
433
434   SILC_LOG_DEBUG(("Encoding channel message payload"));
435
436   /* Calculate length of padding. IV is not included into the calculation
437      since it is not encrypted. */
438   mac_len = silc_hmac_len(hmac);
439   data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
440   len = 6 + data_len + mac_len;
441   pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
442
443   /* Allocate channel payload buffer */
444   len += pad_len + iv_len;
445   buffer = silc_buffer_alloc(len);
446   if (!buffer)
447     return NULL;
448
449   /* Generate padding */
450   if (rng) {
451     for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
452   } else {
453     for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
454   }
455
456   /* Encode the Channel Message Payload */
457   silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
458   silc_buffer_format(buffer, 
459                      SILC_STR_UI_SHORT(flags),
460                      SILC_STR_UI_SHORT(data_len),
461                      SILC_STR_UI_XNSTRING(data, data_len),
462                      SILC_STR_UI_SHORT(pad_len),
463                      SILC_STR_UI_XNSTRING(pad, pad_len),
464                      SILC_STR_END);
465
466   memset(pad, 0, sizeof(pad));
467
468   if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
469                                             buffer->truelen, iv, iv_len,
470                                             cipher, hmac)) {
471     silc_buffer_free(buffer);
472     return NULL;
473   }
474
475   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
476
477   return buffer;
478 }
479
480 /* Free's Channel Message Payload */
481
482 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
483 {
484   if (payload->data) {
485     memset(payload->data, 0, payload->data_len);
486     silc_free(payload->data);
487   }
488   silc_free(payload);
489 }
490
491 /* Return flags */
492
493 SilcMessageFlags
494 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
495 {
496   return payload->flags;
497 }
498
499 /* Return data */
500
501 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
502                                              SilcUInt32 *data_len)
503 {
504   if (data_len)
505     *data_len = payload->data_len;
506
507   return payload->data;
508 }
509
510 /* Return MAC. The caller knows the length of the MAC */
511
512 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
513 {
514   return payload->mac;
515 }
516
517 /* Return IV. The caller knows the length of the IV */
518
519 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
520 {
521   return payload->iv;
522 }
523
524 /******************************************************************************
525
526                              Channel Key Payload
527
528 ******************************************************************************/
529
530 /* Channel Key Payload structrue. Channel keys are parsed from SILC
531    packets into this structure. */
532 struct SilcChannelKeyPayloadStruct {
533   SilcUInt16 id_len;
534   unsigned char *id;
535   SilcUInt16 cipher_len;
536   unsigned char *cipher;
537   SilcUInt16 key_len;
538   unsigned char *key;
539 };
540
541 /* Parses channel key payload returning new channel key payload structure */
542
543 SilcChannelKeyPayload 
544 silc_channel_key_payload_parse(const unsigned char *payload,
545                                SilcUInt32 payload_len)
546 {
547   SilcBufferStruct buffer;
548   SilcChannelKeyPayload newp;
549   int ret;
550
551   SILC_LOG_DEBUG(("Parsing channel key payload"));
552
553   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
554   newp = silc_calloc(1, sizeof(*newp));
555   if (!newp)
556     return NULL;
557
558   /* Parse the Channel Key Payload */
559   ret =
560     silc_buffer_unformat(&buffer,
561                          SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
562                          SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher, 
563                                                      &newp->cipher_len),
564                          SILC_STR_UI16_NSTRING_ALLOC(&newp->key, 
565                                                      &newp->key_len),
566                          SILC_STR_END);
567   if (ret == -1)
568     goto err;
569
570   if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
571     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
572     goto err;
573   }
574
575   return newp;
576
577  err:
578   if (newp->id)
579     silc_free(newp->id);
580   if (newp->cipher)
581     silc_free(newp->cipher);
582   if (newp->key)
583     silc_free(newp->key);
584   silc_free(newp);
585   return NULL;
586 }
587
588 /* Encodes channel key payload into a buffer and returns it. This is used 
589    to add channel key payload into a packet. */
590
591 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
592                                            const unsigned char *id,
593                                            SilcUInt16 cipher_len,
594                                            const unsigned char *cipher,
595                                            SilcUInt16 key_len,
596                                            const unsigned char *key)
597 {
598   SilcBuffer buffer;
599   SilcUInt32 len;
600
601   SILC_LOG_DEBUG(("Encoding channel key payload"));
602
603   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
604      2 + cipher */
605   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
606   buffer = silc_buffer_alloc_size(len);
607   if (!buffer)
608     return NULL;
609
610   /* Encode the Channel Payload */
611   silc_buffer_format(buffer, 
612                      SILC_STR_UI_SHORT(id_len),
613                      SILC_STR_UI_XNSTRING(id, id_len),
614                      SILC_STR_UI_SHORT(cipher_len),
615                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
616                      SILC_STR_UI_SHORT(key_len),
617                      SILC_STR_UI_XNSTRING(key, key_len),
618                      SILC_STR_END);
619
620   return buffer;
621 }
622
623 /* Frees Channel Key Payload */
624
625 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
626 {
627   if (payload) {
628     silc_free(payload->id);
629     silc_free(payload->cipher);
630     if (payload->key) {
631       memset(payload->key, 0, payload->key_len);
632       silc_free(payload->key);
633     }
634     silc_free(payload);
635   }
636 }
637
638 /* Return ID */
639
640 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
641                                        SilcUInt32 *id_len)
642 {
643   if (id_len)
644     *id_len = payload->id_len;
645
646   return payload->id;
647 }
648
649 /* Return cipher name */
650
651 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
652                                            SilcUInt32 *cipher_len)
653 {
654   if (cipher_len)
655     *cipher_len = payload->cipher_len;
656
657   return payload->cipher;
658 }
659
660 /* Return key */
661
662 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
663                                         SilcUInt32 *key_len)
664 {
665   if (key_len)
666     *key_len = payload->key_len;
667
668   return payload->key;
669 }