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