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