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 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
234
235 /* Channel Message Payload structure. Contents of this structure is parsed
236    from SILC packets. */
237 struct SilcChannelMessagePayloadStruct {
238   SilcMessageFlags flags;
239   SilcUInt16 data_len;
240   unsigned char *data;
241   unsigned char *mac;
242   unsigned char *iv;
243 };
244
245 /* Decrypts the channel message payload. First push the IV out of the
246    packet. The IV is used in the decryption process. Then decrypt the
247    message. After decyprtion, take the MAC from the decrypted packet, 
248    compute MAC and compare the MACs.  If they match, the decryption was
249    successful and we have the channel message ready to be displayed. */
250
251 bool silc_channel_message_payload_decrypt(unsigned char *data,
252                                           size_t data_len,
253                                           SilcCipher cipher,
254                                           SilcHmac hmac)
255 {
256   SilcUInt32 iv_len, mac_len;
257   unsigned char *end, *mac, mac2[32];
258   unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
259
260   /* Push the IV out of the packet, and copy the IV since we do not want
261      to modify the original data buffer. */
262   end = data + data_len;
263   iv_len = silc_cipher_get_block_len(cipher);
264   memcpy(iv, end - iv_len, iv_len);
265
266   /* Allocate destination decryption buffer since we do not want to modify
267      the original data buffer, since we might want to call this function 
268      many times for same payload. */
269   if (hmac) {
270     dst = silc_calloc(data_len - iv_len, sizeof(*dst));
271     if (!dst)
272       return FALSE;
273   } else {
274     dst = data;
275   }
276
277   /* Decrypt the channel message */
278   silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
279
280   if (hmac) {
281     /* Take the MAC */
282     end = dst + (data_len - iv_len);
283     mac_len = silc_hmac_len(hmac);
284     mac = (end - mac_len);
285
286     /* Check the MAC of the message */
287     SILC_LOG_DEBUG(("Checking channel message MACs"));
288     silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
289     if (memcmp(mac, mac2, mac_len)) {
290       SILC_LOG_DEBUG(("Channel message MACs does not match"));
291       silc_free(dst);
292       return FALSE;
293     }
294     SILC_LOG_DEBUG(("MAC is Ok"));
295
296     /* Now copy the decrypted data into the buffer since it is verified
297        it decrypted correctly. */
298     memcpy(data, dst, data_len - iv_len);
299     memset(dst, 0, data_len - iv_len);
300     silc_free(dst);
301   }
302
303   return TRUE;
304 }
305
306 /* Parses channel message payload returning new channel payload structure.
307    This also decrypts it and checks the MAC. */
308
309 SilcChannelMessagePayload 
310 silc_channel_message_payload_parse(unsigned char *payload,
311                                    SilcUInt32 payload_len,
312                                    SilcCipher cipher,
313                                    SilcHmac hmac)
314 {
315   SilcBufferStruct buffer;
316   SilcChannelMessagePayload newp;
317   int ret;
318   SilcUInt32 iv_len, mac_len;
319
320   SILC_LOG_DEBUG(("Parsing channel message payload"));
321
322   silc_buffer_set(&buffer, payload, payload_len);
323
324   /* Decrypt the payload */
325   ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
326                                              cipher, hmac);
327   if (ret == FALSE)
328     return NULL;
329
330   iv_len = silc_cipher_get_block_len(cipher);
331   mac_len = silc_hmac_len(hmac);
332
333   newp = silc_calloc(1, sizeof(*newp));
334   if (!newp)
335     return NULL;
336
337   /* Parse the Channel Message Payload. Ignore the padding. */
338   ret = silc_buffer_unformat(&buffer,
339                              SILC_STR_UI_SHORT(&newp->flags),
340                              SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
341                                                          &newp->data_len),
342                              SILC_STR_UI16_NSTRING(NULL, NULL),
343                              SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
344                              SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
345                              SILC_STR_END);
346   if (ret == -1)
347     goto err;
348
349   if (newp->data_len > buffer.len) {
350     SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
351                     "packet dropped"));
352     goto err;
353   }
354
355   return newp;
356
357  err:
358   silc_channel_message_payload_free(newp);
359   return NULL;
360 }
361
362 /* Encodes channel message payload into a buffer and returns it. This is used 
363    to add channel message payload into a packet. As the channel payload is
364    encrypted separately from other parts of the packet padding must
365    be applied to the payload. */
366
367 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
368                                                SilcUInt16 data_len,
369                                                const unsigned char *data,
370                                                SilcUInt16 iv_len,
371                                                unsigned char *iv,
372                                                SilcCipher cipher,
373                                                SilcHmac hmac)
374 {
375   int i;
376   SilcBuffer buffer;
377   SilcUInt32 len, pad_len, mac_len;
378   unsigned char pad[16];
379   unsigned char mac[32];
380
381   SILC_LOG_DEBUG(("Encoding channel message payload"));
382
383   /* Calculate length of padding. IV is not included into the calculation
384      since it is not encrypted. */
385   mac_len = silc_hmac_len(hmac);
386   len = 6 + data_len + mac_len;
387   pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
388
389   /* Allocate channel payload buffer */
390   len += pad_len + iv_len;
391   buffer = silc_buffer_alloc(len);
392   if (!buffer)
393     return NULL;
394
395   /* Generate padding */
396   for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
397
398   /* Encode the Channel Message Payload */
399   silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
400   silc_buffer_format(buffer, 
401                      SILC_STR_UI_SHORT(flags),
402                      SILC_STR_UI_SHORT(data_len),
403                      SILC_STR_UI_XNSTRING(data, data_len),
404                      SILC_STR_UI_SHORT(pad_len),
405                      SILC_STR_UI_XNSTRING(pad, pad_len),
406                      SILC_STR_END);
407
408   /* Compute the MAC of the channel message data */
409   silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
410
411   /* Put rest of the data to the payload */
412   silc_buffer_pull_tail(buffer, mac_len + iv_len);
413   silc_buffer_pull(buffer, 6 + data_len + pad_len);
414   silc_buffer_format(buffer, 
415                      SILC_STR_UI_XNSTRING(mac, mac_len),
416                      SILC_STR_UI_XNSTRING(iv, iv_len),
417                      SILC_STR_END);
418   silc_buffer_push(buffer, 6 + data_len + pad_len);
419
420   /* Encrypt payload of the packet. This is encrypted with the channel key. */
421   silc_cipher_encrypt(cipher, buffer->data, buffer->data, 
422                       buffer->len - iv_len, iv);
423
424   memset(pad, 0, sizeof(pad));
425   memset(mac, 0, sizeof(mac));
426
427   return buffer;
428 }
429
430 /* Free's Channel Message Payload */
431
432 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
433 {
434   if (payload->data) {
435     memset(payload->data, 0, payload->data_len);
436     silc_free(payload->data);
437   }
438   silc_free(payload);
439 }
440
441 /* Return flags */
442
443 SilcMessageFlags
444 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
445 {
446   return payload->flags;
447 }
448
449 /* Return data */
450
451 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
452                                              SilcUInt32 *data_len)
453 {
454   if (data_len)
455     *data_len = payload->data_len;
456
457   return payload->data;
458 }
459
460 /* Return MAC. The caller knows the length of the MAC */
461
462 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
463 {
464   return payload->mac;
465 }
466
467 /* Return IV. The caller knows the length of the IV */
468
469 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
470 {
471   return payload->iv;
472 }
473
474 /******************************************************************************
475
476                              Channel Key Payload
477
478 ******************************************************************************/
479
480 /* Channel Key Payload structrue. Channel keys are parsed from SILC
481    packets into this structure. */
482 struct SilcChannelKeyPayloadStruct {
483   SilcUInt16 id_len;
484   unsigned char *id;
485   SilcUInt16 cipher_len;
486   unsigned char *cipher;
487   SilcUInt16 key_len;
488   unsigned char *key;
489 };
490
491 /* Parses channel key payload returning new channel key payload structure */
492
493 SilcChannelKeyPayload 
494 silc_channel_key_payload_parse(const unsigned char *payload,
495                                SilcUInt32 payload_len)
496 {
497   SilcBufferStruct buffer;
498   SilcChannelKeyPayload newp;
499   int ret;
500
501   SILC_LOG_DEBUG(("Parsing channel key payload"));
502
503   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
504   newp = silc_calloc(1, sizeof(*newp));
505   if (!newp)
506     return NULL;
507
508   /* Parse the Channel Key Payload */
509   ret =
510     silc_buffer_unformat(&buffer,
511                          SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
512                          SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher, 
513                                                      &newp->cipher_len),
514                          SILC_STR_UI16_NSTRING_ALLOC(&newp->key, 
515                                                      &newp->key_len),
516                          SILC_STR_END);
517   if (ret == -1)
518     goto err;
519
520   if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
521     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
522     goto err;
523   }
524
525   return newp;
526
527  err:
528   if (newp->id)
529     silc_free(newp->id);
530   if (newp->cipher)
531     silc_free(newp->cipher);
532   if (newp->key)
533     silc_free(newp->key);
534   silc_free(newp);
535   return NULL;
536 }
537
538 /* Encodes channel key payload into a buffer and returns it. This is used 
539    to add channel key payload into a packet. */
540
541 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
542                                            const unsigned char *id,
543                                            SilcUInt16 cipher_len,
544                                            const unsigned char *cipher,
545                                            SilcUInt16 key_len,
546                                            const unsigned char *key)
547 {
548   SilcBuffer buffer;
549   SilcUInt32 len;
550
551   SILC_LOG_DEBUG(("Encoding channel key payload"));
552
553   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
554      2 + cipher */
555   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
556   buffer = silc_buffer_alloc_size(len);
557   if (!buffer)
558     return NULL;
559
560   /* Encode the Channel Payload */
561   silc_buffer_format(buffer, 
562                      SILC_STR_UI_SHORT(id_len),
563                      SILC_STR_UI_XNSTRING(id, id_len),
564                      SILC_STR_UI_SHORT(cipher_len),
565                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
566                      SILC_STR_UI_SHORT(key_len),
567                      SILC_STR_UI_XNSTRING(key, key_len),
568                      SILC_STR_END);
569
570   return buffer;
571 }
572
573 /* Frees Channel Key Payload */
574
575 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
576 {
577   if (payload) {
578     silc_free(payload->id);
579     silc_free(payload->cipher);
580     if (payload->key) {
581       memset(payload->key, 0, payload->key_len);
582       silc_free(payload->key);
583     }
584     silc_free(payload);
585   }
586 }
587
588 /* Return ID */
589
590 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
591                                        SilcUInt32 *id_len)
592 {
593   if (id_len)
594     *id_len = payload->id_len;
595
596   return payload->id;
597 }
598
599 /* Return cipher name */
600
601 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
602                                            SilcUInt32 *cipher_len)
603 {
604   if (cipher_len)
605     *cipher_len = payload->cipher_len;
606
607   return payload->cipher;
608 }
609
610 /* Return key */
611
612 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
613                                         SilcUInt32 *key_len)
614 {
615   if (key_len)
616     *key_len = payload->key_len;
617
618   return payload->key;
619 }