Code auditing weekend results and fixes committing.
[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 - 2000 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 and Channel Key Payload implementations. */
21 /* $Id$ */
22
23 #include "silcincludes.h"
24 #include "silcchannel.h"
25
26 /******************************************************************************
27
28                               Channel Payload
29
30 ******************************************************************************/
31
32 /* Channel Payload structure. Contents of this structure is parsed
33    from SILC packets. */
34 struct SilcChannelPayloadStruct {
35   unsigned short data_len;
36   unsigned char *data;
37   unsigned short iv_len;
38   unsigned char *iv;
39 };
40
41 /* Parses channel payload returning new channel payload structure */
42
43 SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer)
44 {
45   SilcChannelPayload new;
46   int ret;
47
48   SILC_LOG_DEBUG(("Parsing channel payload"));
49
50   new = silc_calloc(1, sizeof(*new));
51
52   /* Parse the Channel Payload. Ignore padding and IV, we don't need
53      them. */
54   ret = silc_buffer_unformat(buffer,
55                              SILC_STR_UI16_NSTRING_ALLOC(&new->data, 
56                                                          &new->data_len),
57                              SILC_STR_UI16_NSTRING_ALLOC(NULL, NULL),
58                              SILC_STR_END);
59   if (ret == -1)
60     goto err;
61
62   if (new->data_len < 1 || new->data_len > buffer->len) {
63     SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
64     goto err;
65   }
66
67   return new;
68
69  err:
70   if (new->data)
71     silc_free(new->data);
72   if (new->iv)
73     silc_free(new->iv);
74   silc_free(new);
75   return NULL;
76 }
77
78 /* Encodes channel payload into a buffer and returns it. This is used 
79    to add channel payload into a packet. As the channel payload is
80    encrypted separately from other parts of the packet padding must
81    be applied to the payload. */
82
83 SilcBuffer silc_channel_payload_encode(unsigned short data_len,
84                                        unsigned char *data,
85                                        unsigned short iv_len,
86                                        unsigned char *iv,
87                                        SilcRng rng)
88 {
89   int i;
90   SilcBuffer buffer;
91   unsigned int len, pad_len;
92   unsigned char pad[SILC_PACKET_MAX_PADLEN];
93
94   SILC_LOG_DEBUG(("Encoding channel payload"));
95
96   /* Calculate length of padding. IV is not included into the calculation
97      since it is not encrypted. */
98   len = 2 + data_len + 2;
99   pad_len = SILC_PACKET_PADLEN((len + 2));
100
101   /* Allocate channel payload buffer */
102   len += pad_len;
103   buffer = silc_buffer_alloc(len + iv_len);
104   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
105
106   /* Generate padding */
107   for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte(rng);
108
109   /* Encode the Channel Payload */
110   silc_buffer_format(buffer, 
111                      SILC_STR_UI_SHORT(data_len),
112                      SILC_STR_UI_XNSTRING(data, data_len),
113                      SILC_STR_UI_SHORT(pad_len),
114                      SILC_STR_UI_XNSTRING(pad, pad_len),
115                      SILC_STR_UI_XNSTRING(iv, iv_len),
116                      SILC_STR_END);
117
118   memset(pad, 0, pad_len);
119   return buffer;
120 }
121
122 /* Free's Channel Payload */
123
124 void silc_channel_payload_free(SilcChannelPayload payload)
125 {
126   if (payload) {
127     if (payload->data)
128       silc_free(payload->data);
129     if (payload->iv)
130       silc_free(payload->iv);
131     silc_free(payload);
132   }
133 }
134
135 /* Return data */
136
137 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
138                                      unsigned int *data_len)
139 {
140   if (data_len)
141     *data_len = payload->data_len;
142
143   return payload->data;
144 }
145
146 /* Return initial vector */
147
148 unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
149                                    unsigned int *iv_len)
150 {
151   if (iv_len)
152     *iv_len = payload->iv_len;
153
154   return payload->iv;
155 }
156
157 /******************************************************************************
158
159                              Channel Key Payload
160
161 ******************************************************************************/
162
163 /* Channel Key Payload structrue. Channel keys are parsed from SILC
164    packets into this structure. */
165 struct SilcChannelKeyPayloadStruct {
166   unsigned short id_len;
167   unsigned char *id;
168   unsigned short cipher_len;
169   unsigned char *cipher;
170   unsigned short key_len;
171   unsigned char *key;
172 };
173
174 /* Parses channel key payload returning new channel key payload structure */
175
176 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
177 {
178   SilcChannelKeyPayload new;
179   int ret;
180
181   SILC_LOG_DEBUG(("Parsing channel key payload"));
182
183   new = silc_calloc(1, sizeof(*new));
184
185   /* Parse the Channel Key Payload */
186   ret =
187     silc_buffer_unformat(buffer,
188                          SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
189                          SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
190                                                      &new->cipher_len),
191                          SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
192                          SILC_STR_END);
193   if (ret == -1)
194     goto err;
195
196   if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
197     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
198     goto err;
199   }
200
201   return new;
202
203  err:
204   if (new->id)
205     silc_free(new->id);
206   if (new->cipher)
207     silc_free(new->cipher);
208   if (new->key)
209     silc_free(new->key);
210   silc_free(new);
211   return NULL;
212 }
213
214 /* Encodes channel key payload into a buffer and returns it. This is used 
215    to add channel key payload into a packet. */
216
217 SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
218                                            unsigned char *id,
219                                            unsigned short cipher_len,
220                                            unsigned char *cipher,
221                                            unsigned short key_len,
222                                            unsigned char *key)
223 {
224   SilcBuffer buffer;
225   unsigned int len;
226
227   SILC_LOG_DEBUG(("Encoding channel key payload"));
228
229   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
230      2 + cipher */
231   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
232   buffer = silc_buffer_alloc(len);
233
234   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
235
236   /* Encode the Channel Payload */
237   silc_buffer_format(buffer, 
238                      SILC_STR_UI_SHORT(id_len),
239                      SILC_STR_UI_XNSTRING(id, id_len),
240                      SILC_STR_UI_SHORT(cipher_len),
241                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
242                      SILC_STR_UI_SHORT(key_len),
243                      SILC_STR_UI_XNSTRING(key, key_len),
244                      SILC_STR_END);
245
246   return buffer;
247 }
248
249 /* Free's Channel Key Payload */
250
251 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
252 {
253   if (payload) {
254     if (payload->id)
255       silc_free(payload->id);
256     if (payload->cipher)
257       silc_free(payload->cipher);
258     if (payload->key) {
259       memset(payload->key, 0, payload->key_len);
260       silc_free(payload->key);
261     }
262     silc_free(payload);
263   }
264 }
265
266 /* Return ID */
267
268 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
269                                        unsigned int *id_len)
270 {
271   if (id_len)
272     *id_len = payload->id_len;
273
274   return payload->id;
275 }
276
277 /* Return cipher name */
278
279 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
280                                            unsigned int *cipher_len)
281 {
282   if (cipher_len)
283     *cipher_len = payload->cipher_len;
284
285   return payload->cipher;
286 }
287
288 /* Return key */
289
290 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
291                                         unsigned int *key_len)
292 {
293   if (key_len)
294     *key_len = payload->key_len;
295
296   return payload->key;
297 }