+/* $OpenBSD: packet.c,v 1.148 2007/06/07 19:37:34 pvalchev Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
*/
#include "includes.h"
-RCSID("$OpenBSD: packet.c,v 1.120 2005/10/30 08:52:17 djm Exp $");
-
+
+#include <sys/types.h>
#include "openbsd-compat/sys-queue.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
#include "xmalloc.h"
#include "buffer.h"
#include "packet.h"
-#include "bufaux.h"
#include "crc32.h"
-#include "getput.h"
-
#include "compress.h"
#include "deattack.h"
#include "channels.h"
-
#include "compat.h"
#include "ssh1.h"
#include "ssh2.h"
-
#include "cipher.h"
+#include "key.h"
#include "kex.h"
#include "mac.h"
#include "log.h"
return (cipher_get_keyiv_len(cc));
}
+
void
packet_set_iv(int mode, u_char *dat)
{
cipher_set_keyiv(cc, dat);
}
+
int
packet_get_ssh1_cipher(void)
{
buffer_append(&outgoing_packet, &ch, 1);
}
+
void
packet_put_int(u_int value)
{
buffer_put_int(&outgoing_packet, value);
}
+
void
packet_put_string(const void *buf, u_int len)
{
buffer_put_string(&outgoing_packet, buf, len);
}
+
void
packet_put_cstring(const char *str)
{
buffer_put_cstring(&outgoing_packet, str);
}
+
void
packet_put_raw(const void *buf, u_int len)
{
buffer_append(&outgoing_packet, buf, len);
}
+
void
packet_put_bignum(BIGNUM * value)
{
buffer_put_bignum(&outgoing_packet, value);
}
+
void
packet_put_bignum2(BIGNUM * value)
{
/* Add check bytes. */
checksum = ssh_crc32(buffer_ptr(&outgoing_packet),
buffer_len(&outgoing_packet));
- PUT_32BIT(buf, checksum);
+ put_u32(buf, checksum);
buffer_append(&outgoing_packet, buf, 4);
#ifdef PACKET_DEBUG
#endif
/* Append to output. */
- PUT_32BIT(buf, len);
+ put_u32(buf, len);
buffer_append(&output, buf, 4);
cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
enc = &newkeys[mode]->enc;
mac = &newkeys[mode]->mac;
comp = &newkeys[mode]->comp;
- memset(mac->key, 0, mac->key_len);
+ mac_clear(mac);
xfree(enc->name);
xfree(enc->iv);
xfree(enc->key);
enc = &newkeys[mode]->enc;
mac = &newkeys[mode]->mac;
comp = &newkeys[mode]->comp;
- if (mac->md != NULL)
+ if (mac_init(mac) == 0)
mac->enabled = 1;
DBG(debug("cipher_init_context: %d", mode));
cipher_init(cc, enc->cipher, enc->key, enc->key_len,
enc->iv, enc->block_size, crypt_type);
/* Deleting the keys does not gain extra security */
/* memset(enc->iv, 0, enc->block_size);
- memset(enc->key, 0, enc->key_len); */
+ memset(enc->key, 0, enc->key_len);
+ memset(mac->key, 0, mac->key_len); */
if ((comp->type == COMP_ZLIB ||
(comp->type == COMP_DELAYED && after_authentication)) &&
comp->enabled == 0) {
/*
* Delayed compression for SSH2 is enabled after authentication:
- * This happans on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent,
+ * This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent,
* and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received.
*/
static void
*/
after_authentication = 1;
for (mode = 0; mode < MODE_MAX; mode++) {
+ /* protocol error: USERAUTH_SUCCESS received before NEWKEYS */
+ if (newkeys[mode] == NULL)
+ continue;
comp = &newkeys[mode]->comp;
if (comp && !comp->enabled && comp->type == COMP_DELAYED) {
packet_init_compression();
/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
-static void
+static int
packet_send2_wrapped(void)
{
u_char type, *cp, *macbuf = NULL;
/* packet_length includes payload, padding and padding length field */
packet_length = buffer_len(&outgoing_packet) - 4;
cp = buffer_ptr(&outgoing_packet);
- PUT_32BIT(cp, packet_length);
+ put_u32(cp, packet_length);
cp[4] = padlen;
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
buffer_len(&outgoing_packet));
/* append unencrypted MAC */
if (mac && mac->enabled)
- buffer_append(&output, (char *)macbuf, mac->mac_len);
+ buffer_append(&output, macbuf, mac->mac_len);
#ifdef PACKET_DEBUG
fprintf(stderr, "encrypted: ");
buffer_dump(&output);
set_newkeys(MODE_OUT);
else if (type == SSH2_MSG_USERAUTH_SUCCESS && server_side)
packet_enable_delayed_compress();
+ return(packet_length);
}
-static void
+static int
packet_send2(void)
{
+ static int packet_length = 0;
static int rekeying = 0;
struct packet *p;
u_char type, *cp;
memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
buffer_init(&outgoing_packet);
TAILQ_INSERT_TAIL(&outgoing, p, next);
- return;
+ return(sizeof(Buffer));
}
}
if (type == SSH2_MSG_KEXINIT)
rekeying = 1;
- packet_send2_wrapped();
+ packet_length = packet_send2_wrapped();
/* after a NEWKEYS message we can send the complete queue */
if (type == SSH2_MSG_NEWKEYS) {
sizeof(Buffer));
TAILQ_REMOVE(&outgoing, p, next);
xfree(p);
- packet_send2_wrapped();
+ packet_length += packet_send2_wrapped();
}
}
+ return(packet_length);
}
-void
+int
packet_send(void)
{
+ int packet_len = 0;
if (compat20)
- packet_send2();
+ packet_len = packet_send2();
else
packet_send1();
DBG(debug("packet_send done"));
+ return(packet_len);
}
/*
char buf[8192];
DBG(debug("packet_read()"));
- setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
+ setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS),
sizeof(fd_mask));
/* Since we are blocking, ensure that all written packets have been sent. */
return SSH_MSG_NONE;
/* Get length of incoming packet. */
cp = buffer_ptr(&input);
- len = GET_32BIT(cp);
+ len = get_u32(cp);
if (len < 1 + 2 + 2 || len > 256 * 1024)
packet_disconnect("Bad packet length %u.", len);
padded_len = (len + 8) & ~7;
* (C)1998 CORE-SDI, Buenos Aires Argentina
* Ariel Futoransky(futo@core-sdi.com)
*/
- if (!receive_context.plaintext &&
- detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED)
- packet_disconnect("crc32 compensation attack: network attack detected");
+ if (!receive_context.plaintext) {
+ switch (detect_attack(buffer_ptr(&input), padded_len)) {
+ case DEATTACK_DETECTED:
+ packet_disconnect("crc32 compensation attack: "
+ "network attack detected");
+ case DEATTACK_DOS_DETECTED:
+ packet_disconnect("deattack denial of "
+ "service detected");
+ }
+ }
/* Decrypt data to incoming_packet. */
buffer_clear(&incoming_packet);
len, buffer_len(&incoming_packet));
cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4;
- stored_checksum = GET_32BIT(cp);
+ stored_checksum = get_u32(cp);
if (checksum != stored_checksum)
packet_disconnect("Corrupted check bytes on input.");
buffer_consume_end(&incoming_packet, 4);
cipher_crypt(&receive_context, cp, buffer_ptr(&input),
block_size);
cp = buffer_ptr(&incoming_packet);
- packet_length = GET_32BIT(cp);
+ packet_length = get_u32(cp);
if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
#ifdef PACKET_DEBUG
buffer_dump(&incoming_packet);
break;
default:
return type;
- break;
}
} else {
type = packet_read_poll1();
logit("Received disconnect from %s: %.400s",
get_remote_ipaddr(), msg);
cleanup_exit(255);
- xfree(msg);
break;
default:
if (type)
DBG(debug("received packet type %d", type));
return type;
- break;
}
}
}
/* Checks if there is any buffered output, and tries to write some of the output. */
-void
+int
packet_write_poll(void)
{
- int len = buffer_len(&output);
+ int len = 0;
+ len = buffer_len(&output);
if (len > 0) {
len = write(connection_out, buffer_ptr(&output), len);
if (len <= 0) {
if (errno == EAGAIN)
- return;
+ return (0);
else
fatal("Write failed: %.100s", strerror(errno));
}
buffer_consume(&output, len);
}
+ return(len);
}
/*
* written.
*/
-void
+int
packet_write_wait(void)
{
fd_set *setp;
+ u_int bytes_sent = 0;
- setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
+ setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS),
sizeof(fd_mask));
- packet_write_poll();
+ bytes_sent += packet_write_poll();
while (packet_have_data_to_write()) {
memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
sizeof(fd_mask));
while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
(errno == EAGAIN || errno == EINTR))
;
- packet_write_poll();
+ bytes_sent += packet_write_poll();
}
xfree(setp);
+ return (bytes_sent);
}
/* Returns true if there is buffered data to write to the connection. */
/* Only set socket options if using a socket. */
if (!packet_connection_is_on_socket())
return;
- if (interactive)
- set_nodelay(connection_in);
+ set_nodelay(connection_in);
packet_set_tos(interactive);
}
for (i = 0; i < nbytes; i++) {
if (i % 4 == 0)
rnd = arc4random();
- packet_put_char(rnd & 0xff);
+ packet_put_char((u_char)rnd & 0xff);
rnd >>= 8;
}
}
-int rekey_requested = 0;
+int rekey_requested = 0;
void
packet_request_rekeying(void)
{
{
after_authentication = 1;
}
+
+int
+packet_authentication_state(void)
+{
+ return(after_authentication);
+}