Initial revision
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.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 /*
21  * Created: Fri Jul 25 18:52:14 1997
22  */
23 /*
24  * $Id$
25  * $Log$
26  * Revision 1.1  2000/06/27 11:36:55  priikone
27  * Initial revision
28  *
29  *
30  */
31
32 #include "silcincludes.h"
33
34 /* Writes data from encrypted buffer to the socket connection. If the
35    data cannot be written at once, it will be written later with a timeout. 
36    The data is written from the data section of the buffer, not from head
37    or tail section. This automatically pulls the data section towards end
38    after writing the data. */
39
40 int silc_packet_write(int sock, SilcBuffer src)
41 {
42   int ret = 0;
43
44   SILC_LOG_DEBUG(("Writing data to socket %d", sock));
45
46   if (src->len > 0) {
47     ret = write(sock, src->data, src->len);
48     if (ret < 0) {
49       if (errno == EAGAIN) {
50         SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
51         return -2;
52       }
53       SILC_LOG_ERROR(("Cannot write to socket: %s", strerror(errno)));
54       return -1;
55     }
56
57     silc_buffer_pull(src, ret);
58   }
59
60   SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
61
62   return ret;
63 }
64
65 /* Reads data from the socket connection into the incoming data buffer.
66    However, this does not parse the packet, it only reads some amount from
67    the network. If there are more data available that can be read at a time
68    the rest of the data will be read later with a timeout and only after
69    that the packet is ready to be parsed. 
70
71    The destination buffer sent as argument must be initialized before 
72    calling this function, and, the data section and the start of the tail
73    section must be same. Ie. we add the read data to the tail section of
74    the buffer hence the data section is the start of the buffer.
75
76    This returns amount of bytes read or -1 on error or -2 on case where
77    all of the data could not be read at once. */
78
79 int silc_packet_read(int sock, SilcBuffer dest)
80 {
81   int len = 0;
82   unsigned char buf[SILC_PACKET_READ_SIZE];
83
84   SILC_LOG_DEBUG(("Reading data from socket %d", sock));
85
86   /* Read the data from the socket. */
87   len = read(sock, buf, sizeof(buf));
88   if (len < 0) {
89     if (errno == EAGAIN) {
90       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
91       return -2;
92     }
93     SILC_LOG_ERROR(("Cannot read from socket: %d", strerror(errno)));
94     return -1;
95   }
96
97   if (!len)
98     return 0;
99
100   /* Insert the data to the buffer. If the data doesn't fit to the 
101      buffer space is allocated for the buffer.  
102      XXX: I don't like this. -Pekka */
103   if (dest) {
104
105     /* If the data doesn't fit we just have to allocate a whole new 
106        data area */
107     if (dest->truelen <= len) {
108
109       /* Free the old buffer */
110       memset(dest->head, 'F', dest->truelen);
111       silc_free(dest->head);
112
113       /* Allocate new data area */
114       len += SILC_PACKET_DEFAULT_SIZE;
115       dest->data = silc_calloc(len, sizeof(char));
116       dest->truelen = len;
117       dest->len = 0;
118       dest->head = dest->data;
119       dest->data = dest->data;
120       dest->tail = dest->data;
121       dest->end = dest->data + dest->truelen;
122       len -= SILC_PACKET_DEFAULT_SIZE;
123     }
124
125     silc_buffer_put_tail(dest, buf, len);
126     silc_buffer_pull_tail(dest, len);
127   }
128
129   SILC_LOG_DEBUG(("Read %d bytes", len));
130
131   return len;
132 }
133
134 /* Encrypts a packet. */
135
136 void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
137                          unsigned int len)
138 {
139   SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)", 
140                   cipher->cipher->name, len, len - 2));
141
142   /* Encrypt the data area of the packet. 3 bytes of the packet
143      are not encrypted. */
144   cipher->cipher->encrypt(cipher->context, buffer->data + 2, 
145                           buffer->data + 2, len - 2, cipher->iv);
146
147 }
148
149 /* Decrypts a packet. */
150
151 void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer, 
152                          unsigned int len)
153 {
154   SILC_LOG_DEBUG(("Decrypting packet, cipher %s, len %d (%d)", 
155                   cipher->cipher->name, len, len - 2));
156
157   /* Decrypt the data area of the packet. 2 bytes of the packet
158      are not decrypted (they are not encrypted). */
159   cipher->cipher->decrypt(cipher->context, buffer->data + 2, 
160                           buffer->data + 2, len - 2, cipher->iv);
161
162 }
163
164 /* Parses the packet. This is called when a whole packet is ready to be
165    parsed. The buffer sent must be already decrypted before calling this 
166    function. The len argument must be the true length of the packet. This 
167    function returns the type of the packet. The data section of the 
168    buffer is parsed, not head or tail sections. */
169
170 SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
171 {
172   SilcBuffer buffer = ctx->buffer;
173   int len;
174
175   SILC_LOG_DEBUG(("Parsing incoming packet"));
176
177   /* Check the length of the buffer */
178   if (buffer->len < SILC_PACKET_MIN_LEN) {
179     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
180     return SILC_PACKET_NONE;
181   }
182
183   /* Parse the buffer. This parses the SILC header of the packet. */
184   len = silc_buffer_unformat(buffer, 
185                              SILC_STR_UI_SHORT(&ctx->truelen),
186                              SILC_STR_UI_CHAR(&ctx->flags),
187                              SILC_STR_UI_CHAR(&ctx->type),
188                              SILC_STR_UI_SHORT(&ctx->src_id_len),
189                              SILC_STR_UI_SHORT(&ctx->dst_id_len),
190                              SILC_STR_UI_CHAR(&ctx->src_id_type),
191                              SILC_STR_END);
192
193   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
194       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
195     SILC_LOG_ERROR(("Bad ID lengths in packet"));
196     return SILC_PACKET_NONE;
197   }
198
199   /* Calculate length of padding in packet */
200   ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
201
202   silc_buffer_pull(buffer, len);
203   silc_buffer_unformat(buffer, 
204                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
205                                                   ctx->src_id_len),
206                        SILC_STR_UI_CHAR(&ctx->dst_id_type),
207                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
208                                                   ctx->dst_id_len),
209                        SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
210                        SILC_STR_END);
211   silc_buffer_push(buffer, len);
212
213   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
214                    ctx->buffer->data, ctx->buffer->len);
215
216   /* Pull SILC header and padding from packet */
217   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
218                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
219
220   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
221
222   return ctx->type;
223 }
224
225 /* Perform special SILC Packet header parsing. This is required to some
226    packet types that have the data payload encrypted with different key
227    than the header area plus padding of the packet. Hence, this parses
228    the header in a way that it does not take the data area into account
229    and parses the header and padding area only. */
230
231 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
232 {
233   SilcBuffer buffer = ctx->buffer;
234   int len, tmplen;
235
236   SILC_LOG_DEBUG(("Parsing incoming packet"));
237
238   /* Check the length of the buffer */
239   if (buffer->len < SILC_PACKET_MIN_LEN) {
240     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
241     return SILC_PACKET_NONE;
242   }
243
244   /* Parse the buffer. This parses the SILC header of the packet. */
245   len = silc_buffer_unformat(buffer, 
246                              SILC_STR_UI_SHORT(&ctx->truelen),
247                              SILC_STR_UI_CHAR(&ctx->flags),
248                              SILC_STR_UI_CHAR(&ctx->type),
249                              SILC_STR_UI_SHORT(&ctx->src_id_len),
250                              SILC_STR_UI_SHORT(&ctx->dst_id_len),
251                              SILC_STR_UI_CHAR(&ctx->src_id_type),
252                              SILC_STR_END);
253
254   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
255       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
256     SILC_LOG_ERROR(("Bad ID lengths in packet"));
257     return SILC_PACKET_NONE;
258   }
259
260   /* Calculate length of padding in packet. As this is special packet
261      the data area is not used in the padding calculation as it won't
262      be decrypted by the caller. */
263   tmplen = SILC_PACKET_HEADER_LEN + ctx->src_id_len + ctx->dst_id_len;
264   ctx->padlen = SILC_PACKET_PADLEN(tmplen);
265
266   silc_buffer_pull(buffer, len);
267   silc_buffer_unformat(buffer, 
268                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
269                                                   ctx->src_id_len),
270                        SILC_STR_UI_CHAR(&ctx->dst_id_type),
271                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
272                                                   ctx->dst_id_len),
273                        SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
274                        SILC_STR_END);
275   silc_buffer_push(buffer, len);
276
277   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
278                    ctx->buffer->data, ctx->buffer->len);
279
280   /* Pull SILC header and padding from packet */
281   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
282                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
283
284   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
285
286   return ctx->type;
287 }
288
289 /* Assembles a new packet to be ready for send out. The buffer sent as
290    argument must include the data to be sent and it must not be encrypted. 
291    The packet also must have enough free space so that the SILC header
292    and padding maybe added to the packet. The packet is encrypted after 
293    this function has returned.
294
295    The buffer sent as argument should be something like following:
296
297    --------------------------------------------
298    | head             | data           | tail |
299    --------------------------------------------
300    ^                  ^
301    58 bytes           x bytes
302
303    So that the SILC header and 1 - 16 bytes of padding can fit to
304    the buffer. After assembly the buffer might look like this:
305
306    --------------------------------------------
307    | data                              |      |
308    --------------------------------------------
309    ^                                   ^
310    Start of assembled packet
311
312    Packet construct is as follows (* = won't be encrypted):
313
314    x bytes       SILC Header
315       2 bytes     Payload length  (*)
316       1 byte      Flags           (*)
317       1 byte      Packet type
318       1 byte      Source ID Type
319       2 bytes     Source ID Length
320       x bytes     Source ID
321       1 byte      Destination ID Type
322       2 bytes     Destination ID Length
323       x bytes     Destination ID
324
325    1 - 16 bytes    Padding
326
327    x bytes        Data payload
328
329    All fields in the packet will be authenticated by MAC. The MAC is
330    not computed here, it must be computed differently before encrypting
331    the packet.
332
333 */
334
335 void silc_packet_assemble(SilcPacketContext *ctx)
336 {
337   unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
338   int i;
339
340   SILC_LOG_DEBUG(("Assembling outgoing packet"));
341   
342   /* Get the true length of the packet. This is saved as payload length
343      into the packet header. This does not include the length of the
344      padding. */
345   if (!ctx->truelen)
346     ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN + 
347       ctx->src_id_len + ctx->dst_id_len;
348
349   /* Calculate the length of the padding. The padding is calculated from
350      the data that will be encrypted. As protocol states 3 first bytes
351      of the packet are not encrypted they are not included in the
352      padding calculation. */
353   if (!ctx->padlen)
354     ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
355
356   /* Put the start of the data section to the right place. */
357   silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
358                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
359
360   /* Get random padding */
361 #if 1
362   for (i = 0; i < ctx->padlen; i++)
363     tmppad[i] = silc_rng_get_byte(ctx->rng);
364 #else
365   /* XXX: For testing - to be removed */
366   memset(tmppad, 65, sizeof(tmppad));
367 #endif
368
369   /* Create the packet. This creates the SILC header and adds padding,
370      rest of the buffer remains as it is. */
371   silc_buffer_format(ctx->buffer, 
372                      SILC_STR_UI_SHORT(ctx->truelen),
373                      SILC_STR_UI_CHAR(ctx->flags),
374                      SILC_STR_UI_CHAR(ctx->type),
375                      SILC_STR_UI_SHORT(ctx->src_id_len),
376                      SILC_STR_UI_SHORT(ctx->dst_id_len),
377                      SILC_STR_UI_CHAR(ctx->src_id_type),
378                      SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
379                      SILC_STR_UI_CHAR(ctx->dst_id_type),
380                      SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
381                      SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
382                      SILC_STR_END);
383
384   SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len), 
385                    ctx->buffer->data, ctx->buffer->len);
386
387   SILC_LOG_DEBUG(("Outgoing packet assembled"));
388 }