5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
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.
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.
21 * Created: Fri Jul 25 18:52:14 1997
26 * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
27 * Importet from internal CVS/Added Log headers.
32 #include "silcincludes.h"
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. */
40 int silc_packet_write(int sock, SilcBuffer src)
44 SILC_LOG_DEBUG(("Writing data to socket %d", sock));
47 ret = write(sock, src->data, src->len);
49 if (errno == EAGAIN) {
50 SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
53 SILC_LOG_ERROR(("Cannot write to socket: %s", strerror(errno)));
57 silc_buffer_pull(src, ret);
60 SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
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.
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.
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. */
79 int silc_packet_read(int sock, SilcBuffer dest)
82 unsigned char buf[SILC_PACKET_READ_SIZE];
84 SILC_LOG_DEBUG(("Reading data from socket %d", sock));
86 /* Read the data from the socket. */
87 len = read(sock, buf, sizeof(buf));
89 if (errno == EAGAIN) {
90 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
93 SILC_LOG_ERROR(("Cannot read from socket: %d", strerror(errno)));
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 */
105 /* If the data doesn't fit we just have to allocate a whole new
107 if (dest->truelen <= len) {
109 /* Free the old buffer */
110 memset(dest->head, 'F', dest->truelen);
111 silc_free(dest->head);
113 /* Allocate new data area */
114 len += SILC_PACKET_DEFAULT_SIZE;
115 dest->data = silc_calloc(len, sizeof(char));
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;
125 silc_buffer_put_tail(dest, buf, len);
126 silc_buffer_pull_tail(dest, len);
129 SILC_LOG_DEBUG(("Read %d bytes", len));
134 /* Encrypts a packet. */
136 void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
139 SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)",
140 cipher->cipher->name, len, len - 2));
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);
149 /* Decrypts a packet. */
151 void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer,
154 SILC_LOG_DEBUG(("Decrypting packet, cipher %s, len %d (%d)",
155 cipher->cipher->name, len, len - 2));
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);
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. */
170 SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
172 SilcBuffer buffer = ctx->buffer;
175 SILC_LOG_DEBUG(("Parsing incoming packet"));
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;
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),
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;
199 /* Calculate length of padding in packet */
200 ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
202 silc_buffer_pull(buffer, len);
203 silc_buffer_unformat(buffer,
204 SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
206 SILC_STR_UI_CHAR(&ctx->dst_id_type),
207 SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
209 SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
211 silc_buffer_push(buffer, len);
213 SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
214 ctx->buffer->data, ctx->buffer->len);
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);
220 SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
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. */
231 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
233 SilcBuffer buffer = ctx->buffer;
236 SILC_LOG_DEBUG(("Parsing incoming packet"));
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;
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),
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;
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);
266 silc_buffer_pull(buffer, len);
267 silc_buffer_unformat(buffer,
268 SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
270 SILC_STR_UI_CHAR(&ctx->dst_id_type),
271 SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
273 SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
275 silc_buffer_push(buffer, len);
277 SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
278 ctx->buffer->data, ctx->buffer->len);
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);
284 SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
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.
295 The buffer sent as argument should be something like following:
297 --------------------------------------------
298 | head | data | tail |
299 --------------------------------------------
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:
306 --------------------------------------------
308 --------------------------------------------
310 Start of assembled packet
312 Packet construct is as follows (* = won't be encrypted):
315 2 bytes Payload length (*)
318 1 byte Source ID Type
319 2 bytes Source ID Length
321 1 byte Destination ID Type
322 2 bytes Destination ID Length
323 x bytes Destination ID
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
335 void silc_packet_assemble(SilcPacketContext *ctx)
337 unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
340 SILC_LOG_DEBUG(("Assembling outgoing packet"));
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
346 ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN +
347 ctx->src_id_len + ctx->dst_id_len;
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. */
354 ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
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);
360 /* Get random padding */
362 for (i = 0; i < ctx->padlen; i++)
363 tmppad[i] = silc_rng_get_byte(ctx->rng);
365 /* XXX: For testing - to be removed */
366 memset(tmppad, 65, sizeof(tmppad));
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),
384 SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len),
385 ctx->buffer->data, ctx->buffer->len);
387 SILC_LOG_DEBUG(("Outgoing packet assembled"));