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