Commit 2d5ab5ac authored by Niels Möller's avatar Niels Möller
Browse files

Moved packet readign and decryption into a read handler.

Rev: src/decrypt.c:1.5(DEAD)
Rev: src/decrypt.h:1.4(DEAD)
Rev: src/read_packet.c:1.1
parent 0e19c562
/* decrypt.c
*
*/
#include "decrypt.h"
#include "werror.h"
#include "xalloc.h"
#define WAIT_HEADER 0
#define WAIT_CONTENTS 1
#define WAIT_MAC 2
#define MIN(a, b) ( ((a)<(b)) ? (a) : (b) )
#define MAX(a, b) ( ((a)>(b)) ? (a) : (b) )
static int do_decrypt(struct decrypt_processor *closure,
struct lsh_string *packet)
{
/* Number of octets n the input packet that have been processed */
UINT32 pos = 0;
while(pos < packet->length)
switch(closure->state)
{
case WAIT_HEADER:
{
UINT32 left = closure->block_size - closure->pos;
UINT32 copy = MIN(left, (packet->length - pos));
memcpy(closure->block_buffer + closure->pos,
packet->data + pos,
copy);
pos += copy;
closure->pos += copy;
if (left == copy)
{
/* Read a full header */
UINT32 length;
/* Decrypt the first block */
closure->decrypt_function(closure->decrypt_state,
closure->block_size, closure->block_buffer,
closure->block_buffer);
length = READ_UINT32(closure->block_buffer);
if (length > closure->max_packet)
return 0;
if ( (length < 12)
|| (length < (closure->block_size - 4))
|| ( (length + 4) % closure->block_size))
return 0;
/* The length of remaining data. Note that the first,
* already decrypted, block contains some of the
* decypted payload. */
closure->recieved
= lsh_string_alloc(length
- (closure->block_size - 4));
closure->pos = 0;
closure->state = WAIT_CONTENTS;
/* Fall through to WAIT_CONTNTS */
}
else
/* Processed all octets of this packet. Still no complete
* header. */
break;
}
case WAIT_CONTENTS:
{
UINT32 left = closure->recieved->length - closure->pos;
UINT32 copy = MIN(left, packet->length - pos);
memcpy(closure->recieved->data + closure->pos,
packet->data + pos,
copy);
pos += copy;
closure->pos += copy;
if (left == copy)
{
/* Read a complete packet (but no MAC yet) */
UINT32 left_overs = closure->block_size - 4;
/* Full packet (including left-overs from the first block) */
struct lsh_string *new
= lsh_string_alloc(closure->recieved->length
+ left_overs);
memcpy(new->data, closure->block_buffer + 4,
left_overs);
closure->decrypt_function(closure->decrypt_state,
closure->recieved->length,
closure->recieved->data,
new->data + left_overs);
lsh_string_free(closure->recieved);
closure->recieved = new;
if (closure->mac_size)
closure->mac_function(closure->mac_state,
new->length,
new->data,
closure->block_buffer);
closure->pos = 0;
closure->state = WAIT_MAC;
/* Fall through */
}
else
/* Processe all octets, but still haven't got a complete packet */
break;
}
case WAIT_MAC:
if (closure->mac_size)
{
UINT32 left = closure->mac_size - closure->pos;
UINT32 cmp = MIN(left, packet->length - pos);
if (!memcpy(closure->block_buffer + closure->pos,
packet->data + pos,
cmp))
return 0;
pos += cmp;
closure->pos += cmp;
if (left > cmp)
{
/* Processed all octets, but still haven't received a
complete MAC */
break;
}
}
/* MAC was ok, pass packet on */
if (!apply_processor(closure->c.next, closure->recieved))
return 0;
closure->recieved = NULL;
closure->pos = 0;
closure->state = WAIT_HEADER;
break;
default:
fatal("Internal error");
}
/* Processed all octets of this packet. */
return 1;
}
struct abstract_write *
make_decrypt_processor(struct abstract_write *continuation,
UINT32 max_packet,
unsigned mac_size,
transform_function mac_function,
void *mac_state,
unsigned block_size,
transform_function decrypt_function,
void *decrypt_state)
{
struct decrypt_processor *closure = xalloc(sizeof(struct decrypt_processor)
+ MAX(block_size, mac_size) - 1);
closure->c.p.f = (abstract_write_f) do_decrypt;
closure->c.next = continuation;
/* state */
closure->state = WAIT_HEADER;
closure->pos = 0;
closure->recieved = NULL;
closure->max_packet = max_packet;
closure->mac_size = mac_size;
closure->mac_function = mac_function;
closure->mac_state = mac_state;
closure->block_size = block_size;
closure->decrypt_function = decrypt_function;
closure->decrypt_state = decrypt_state;
return (struct abstract_write *) closure;
}
/* decrypt.h
*
*/
#ifndef LSH_DECRYPT_H_INCLUDED
#define LSH_DECRYPT_H_INCLUDED
#include "transport.h"
#include "crypto_common.h"
/* The input packets to this processor are arbitrary octet strings,
* for instance as returned by read(). The data is collected,
* decrypted, and the (padded) payload is passed on to the next packet
* processor, as soon as a complete packet has been read. */
struct decrypt_processor
{
struct abstract_write_pipe c;
int state;
UINT32 pos;
UINT32 max_packet;
struct lsh_string *recieved;
unsigned mac_size;
transform_function mac_function;
void *mac_state;
unsigned block_size;
transform_function decrypt_function;
void *decrypt_state;
UINT8 block_buffer[1];
};
struct packet_processor *
make_decrypt_processor(struct packet_processor *containing,
UINT32 max_packet,
unsigned mac_size,
transform_function mac_function,
void *mac_state,
unsigned block_size,
transform_function encrypt_function,
void *encrypt_state);
#endif /* LSH_DECRYPT_H_INCLUDED */
/* read_packet.c
*
*/
#include "read_packet.h"
#define WAIT_HEADER 0
#define WAIT_CONTENTS 1
#define WAIT_MAC 2
static struct read_handler *do_read_packet(struct read_packet *closure,
struct abstract_read *read)
{
while(1)
{
switch(closure->state)
{
case WAIT_HEADER:
{
UINT32 left = closure->crypto->block_size - closure->pos;
int n;
if (!closure->buffer)
{
closure->buffer = lsh_string_alloc(crypt->block_size);
closure->pos = 0;
}
n = A_READ(read, closure->buffer + closure->pos, left);
switch(n)
{
case 0:
return closure;
case A_FAIL:
werror("do_read_packet: read() failed, %s\n", strerror(errno));
/* Fall through */
case A_EOF:
/* FIXME: Free associated resources! */
return 0;
}
closure->pos += n;
/* Read a complete block? */
if (n == left)
{
UINT32 length;
CRYPT(closure->crypto,
closure->crypto->block_size,
closure->buffer->data,
closure->buffer->data);
length = READ_UINT32(closure->buffer->data);
if (length > closure->max_packet)
return 0;
if ( (length < 12)
|| (length < (closure->block_size - 4))
|| ( (length + 4) % closure->block_size))
return 0;
/* Process this block before the length field is lost. */
if (closure->mac)
{
UINT8 s[4];
WRITE_UINT32(s, closure->sequence_number);
UPDATE(closure->mac, 4, s);
UPDATE(closure->mac,
closure->buffer->length,
closure->buffer->data);
}
/* Allocate full packet */
closure->buffer = ssh_format("%ls%lr",
closure->block_size - 4,
closure->buffer->data + 4,
length, &closure->crypt_pos);
/* FIXME: Is this needed anywhere? */
closure->buffer->sequence_number = closure->sequence_number++;
closure->pos = 4;
closure->state = WAIT_CONTENTS;
/* Fall through */
}
else
/* Try reading some more */
break;
}
case WAIT_CONTENTS:
{
UINT32 left = closure->buffer->length - closure->pos;
int n = A_READ(read, closure->buffer->data + closure->pos, left);
switch(n)
{
case 0:
return closure;
case A_FAIL:
werror("do_read_packet: read() failed, %s\n", strerror(errno));
/* Fall through */
case A_EOF:
/* FIXME: Free associated resources! */
return 0;
}
closure->pos += n;
/* Read a complete packet? */
if (n == left)
{
CRYPT(closure->crypto,
closure->buffer->length - closure->crypt_pos,
closure->buffer->data + closure->crypt_pos,
closure->buffer->data + closure->crypt_pos);
if (closure->mac)
{
UPDATE(closure->mac,
closure->buffer->length - closure->crypt_pos,
closure->buffer->data + closure->crypt_pos);
DIGEST(closure->mac,
closure->computed_mac);
}
closure->state = WAIT_MAC;
closure->pos = 0;
/* Fall through */
}
else
/* Try reading some more */
break;
}
case WAIT_MAC:
if (closure->mac_size)
{
UINT32 left = closure->mac->mac_size - closure->pos;
UINT8 *mac = alloca(left);
int n = A_READ(read, mac, left);
switch(n)
{
case 0:
return closure;
case A_FAIL:
werror("do_read_packet: read() failed, %s\n",
strerror(errno));
/* Fall through */
case A_EOF:
/* FIXME: Free associated resources! */
return 0;
}
if (!memcpy(mac,
closure->computed_mac + closure->pos,
n))
/* FIXME: Free resources */
return 0;
closure->pos += n;
if (n < left)
/* Try reading more */
break;
}
/* MAC was ok, send packet on */
if (!A_WRITE(closure->handler, closure->buffer))
/* FIXME: What now? */
return 0;
closure->buffer = NULL;
state = WAIT_HEADER;
break;
default:
fatal("Internal error\n");
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment