- Get rid of decryptreadbuf, just decrypt in-place with readbuf

- Share make_mac function for both packet creation and validation
- Split recv/trans parts of key_context into their own structures

--HG--
extra : convert_revision : 043bc598c76ed43625987e6937e32238f7ed6240
This commit is contained in:
Matt Johnston 2009-03-01 16:15:57 +00:00
parent 8e72bbaa9d
commit ff763e4005
5 changed files with 175 additions and 211 deletions

View File

@ -272,8 +272,8 @@ void gen_new_keys() {
recv_IV = S2C_IV; recv_IV = S2C_IV;
trans_key = C2S_key; trans_key = C2S_key;
recv_key = S2C_key; recv_key = S2C_key;
C2S_keysize = ses.newkeys->trans_algo_crypt->keysize; C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
S2C_keysize = ses.newkeys->recv_algo_crypt->keysize; S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
mactransletter = 'E'; mactransletter = 'E';
macrecvletter = 'F'; macrecvletter = 'F';
} else { } else {
@ -281,8 +281,8 @@ void gen_new_keys() {
recv_IV = C2S_IV; recv_IV = C2S_IV;
trans_key = S2C_key; trans_key = S2C_key;
recv_key = C2S_key; recv_key = C2S_key;
C2S_keysize = ses.newkeys->recv_algo_crypt->keysize; C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
S2C_keysize = ses.newkeys->trans_algo_crypt->keysize; S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
mactransletter = 'F'; mactransletter = 'F';
macrecvletter = 'E'; macrecvletter = 'E';
} }
@ -292,31 +292,33 @@ void gen_new_keys() {
hashkeys(C2S_key, C2S_keysize, &hs, 'C'); hashkeys(C2S_key, C2S_keysize, &hs, 'C');
hashkeys(S2C_key, S2C_keysize, &hs, 'D'); hashkeys(S2C_key, S2C_keysize, &hs, 'D');
recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name); recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
if (recv_cipher < 0) if (recv_cipher < 0)
dropbear_exit("crypto error"); dropbear_exit("crypto error");
if (ses.newkeys->recv_crypt_mode->start(recv_cipher, if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
recv_IV, recv_key, recv_IV, recv_key,
ses.newkeys->recv_algo_crypt->keysize, 0, ses.newkeys->recv.algo_crypt->keysize, 0,
&ses.newkeys->recv_cipher_state) != CRYPT_OK) { &ses.newkeys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error"); dropbear_exit("crypto error");
} }
trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name); trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
if (trans_cipher < 0) if (trans_cipher < 0)
dropbear_exit("crypto error"); dropbear_exit("crypto error");
if (ses.newkeys->trans_crypt_mode->start(trans_cipher, if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
trans_IV, trans_key, trans_IV, trans_key,
ses.newkeys->trans_algo_crypt->keysize, 0, ses.newkeys->trans.algo_crypt->keysize, 0,
&ses.newkeys->trans_cipher_state) != CRYPT_OK) { &ses.newkeys->trans.cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error"); dropbear_exit("crypto error");
} }
/* MAC keys */ /* MAC keys */
hashkeys(ses.newkeys->transmackey, hashkeys(ses.newkeys->trans.mackey,
ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter); ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
hashkeys(ses.newkeys->recvmackey, hashkeys(ses.newkeys->recv.mackey,
ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter); ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name),
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name),
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
gen_new_zstreams(); gen_new_zstreams();
@ -334,15 +336,15 @@ void gen_new_keys() {
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
int is_compress_trans() { int is_compress_trans() {
return ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone || (ses.authstate.authdone
&& ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY); && ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
} }
int is_compress_recv() { int is_compress_recv() {
return ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone || (ses.authstate.authdone
&& ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY); && ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
} }
/* Set up new zlib compression streams, close the old ones. Only /* Set up new zlib compression streams, close the old ones. Only
@ -350,47 +352,47 @@ int is_compress_recv() {
static void gen_new_zstreams() { static void gen_new_zstreams() {
/* create new zstreams */ /* create new zstreams */
if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { || ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream)); ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv_zstream->zalloc = Z_NULL; ses.newkeys->recv.zstream->zalloc = Z_NULL;
ses.newkeys->recv_zstream->zfree = Z_NULL; ses.newkeys->recv.zstream->zfree = Z_NULL;
if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) { if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
dropbear_exit("zlib error"); dropbear_exit("zlib error");
} }
} else { } else {
ses.newkeys->recv_zstream = NULL; ses.newkeys->recv.zstream = NULL;
} }
if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { || ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream)); ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans_zstream->zalloc = Z_NULL; ses.newkeys->trans.zstream->zalloc = Z_NULL;
ses.newkeys->trans_zstream->zfree = Z_NULL; ses.newkeys->trans.zstream->zfree = Z_NULL;
if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION) if (deflateInit(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION)
!= Z_OK) { != Z_OK) {
dropbear_exit("zlib error"); dropbear_exit("zlib error");
} }
} else { } else {
ses.newkeys->trans_zstream = NULL; ses.newkeys->trans.zstream = NULL;
} }
/* clean up old keys */ /* clean up old keys */
if (ses.keys->recv_zstream != NULL) { if (ses.keys->recv.zstream != NULL) {
if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) { if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */ /* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("crypto error"); dropbear_exit("crypto error");
} }
m_free(ses.keys->recv_zstream); m_free(ses.keys->recv.zstream);
} }
if (ses.keys->trans_zstream != NULL) { if (ses.keys->trans.zstream != NULL) {
if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) { if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */ /* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("crypto error"); dropbear_exit("crypto error");
} }
m_free(ses.keys->trans_zstream); m_free(ses.keys->trans.zstream);
} }
} }
#endif /* DISABLE_ZLIB */ #endif /* DISABLE_ZLIB */
@ -698,36 +700,36 @@ static void read_kex_algos() {
/* Handle the asymmetry */ /* Handle the asymmetry */
if (IS_DROPBEAR_CLIENT) { if (IS_DROPBEAR_CLIENT) {
ses.newkeys->recv_algo_crypt = ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data; (struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->trans_algo_crypt = ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data; (struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->recv_crypt_mode = ses.newkeys->recv.crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode; (struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->trans_crypt_mode = ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode; (struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->recv_algo_mac = ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data; (struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->trans_algo_mac = ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data; (struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->recv_algo_comp = s2c_comp_algo->val; ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
ses.newkeys->trans_algo_comp = c2s_comp_algo->val; ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
} else { } else {
/* SERVER */ /* SERVER */
ses.newkeys->recv_algo_crypt = ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data; (struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->trans_algo_crypt = ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data; (struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->recv_crypt_mode = ses.newkeys->recv.crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode; (struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->trans_crypt_mode = ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode; (struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->recv_algo_mac = ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data; (struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->trans_algo_mac = ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data; (struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->recv_algo_comp = c2s_comp_algo->val; ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
ses.newkeys->trans_algo_comp = s2c_comp_algo->val; ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
} }
/* reserved for future extensions */ /* reserved for future extensions */

View File

@ -78,7 +78,6 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
ses.transseq = 0; ses.transseq = 0;
ses.readbuf = NULL; ses.readbuf = NULL;
ses.decryptreadbuf = NULL;
ses.payload = NULL; ses.payload = NULL;
ses.recvseq = 0; ses.recvseq = 0;
@ -95,22 +94,22 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
/* set all the algos to none */ /* set all the algos to none */
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context)); ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
ses.newkeys = NULL; ses.newkeys = NULL;
ses.keys->recv_algo_crypt = &dropbear_nocipher; ses.keys->recv.algo_crypt = &dropbear_nocipher;
ses.keys->trans_algo_crypt = &dropbear_nocipher; ses.keys->trans.algo_crypt = &dropbear_nocipher;
ses.keys->recv_crypt_mode = &dropbear_mode_none; ses.keys->recv.crypt_mode = &dropbear_mode_none;
ses.keys->trans_crypt_mode = &dropbear_mode_none; ses.keys->trans.crypt_mode = &dropbear_mode_none;
ses.keys->recv_algo_mac = &dropbear_nohash; ses.keys->recv.algo_mac = &dropbear_nohash;
ses.keys->trans_algo_mac = &dropbear_nohash; ses.keys->trans.algo_mac = &dropbear_nohash;
ses.keys->algo_kex = -1; ses.keys->algo_kex = -1;
ses.keys->algo_hostkey = -1; ses.keys->algo_hostkey = -1;
ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE; ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE; ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
ses.keys->recv_zstream = NULL; ses.keys->recv.zstream = NULL;
ses.keys->trans_zstream = NULL; ses.keys->trans.zstream = NULL;
#endif #endif
/* key exchange buffers */ /* key exchange buffers */

198
packet.c
View File

@ -35,9 +35,11 @@
#include "auth.h" #include "auth.h"
#include "channel.h" #include "channel.h"
static void read_packet_init(); static int read_packet_init();
static void make_mac(buffer * clearwritebuf, unsigned char *output_mac); static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
static int checkmac(buffer* hashbuf, buffer* readbuf); buffer * clear_buf, unsigned int clear_len,
unsigned char *output_mac);
static int checkmac();
#define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */ #define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */
#define ZLIB_DECOMPRESS_INCR 100 #define ZLIB_DECOMPRESS_INCR 100
@ -102,18 +104,18 @@ void read_packet() {
unsigned char blocksize; unsigned char blocksize;
TRACE(("enter read_packet")) TRACE(("enter read_packet"))
blocksize = ses.keys->recv_algo_crypt->blocksize; blocksize = ses.keys->recv.algo_crypt->blocksize;
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) { if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
int ret;
/* In the first blocksize of a packet */ /* In the first blocksize of a packet */
/* Read the first blocksize of the packet, so we can decrypt it and /* Read the first blocksize of the packet, so we can decrypt it and
* find the length of the whole packet */ * find the length of the whole packet */
read_packet_init(); ret = read_packet_init();
/* If we don't have the length of decryptreadbuf, we didn't read if (ret == DROPBEAR_FAILURE) {
* a whole blocksize and should exit */ /* didn't read enough to determine the length */
if (ses.decryptreadbuf->len == 0) {
TRACE(("leave read_packet: packetinit done")) TRACE(("leave read_packet: packetinit done"))
return; return;
} }
@ -121,7 +123,6 @@ void read_packet() {
/* Attempt to read the remainder of the packet, note that there /* Attempt to read the remainder of the packet, note that there
* mightn't be any available (EAGAIN) */ * mightn't be any available (EAGAIN) */
dropbear_assert(ses.readbuf != NULL);
maxlen = ses.readbuf->len - ses.readbuf->pos; maxlen = ses.readbuf->len - ses.readbuf->pos;
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen); len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
@ -151,7 +152,9 @@ void read_packet() {
/* Function used to read the initial portion of a packet, and determine the /* Function used to read the initial portion of a packet, and determine the
* length. Only called during the first BLOCKSIZE of a packet. */ * length. Only called during the first BLOCKSIZE of a packet. */
static void read_packet_init() { /* Returns DROPBEAR_SUCCESS if the length is determined,
* DROPBEAR_FAILURE otherwise */
static int read_packet_init() {
unsigned int maxlen; unsigned int maxlen;
int len; int len;
@ -159,14 +162,12 @@ static void read_packet_init() {
unsigned char macsize; unsigned char macsize;
blocksize = ses.keys->recv_algo_crypt->blocksize; blocksize = ses.keys->recv.algo_crypt->blocksize;
macsize = ses.keys->recv_algo_mac->hashsize; macsize = ses.keys->recv.algo_mac->hashsize;
if (ses.readbuf == NULL) { if (ses.readbuf == NULL) {
/* start of a new packet */ /* start of a new packet */
ses.readbuf = buf_new(INIT_READBUF); ses.readbuf = buf_new(INIT_READBUF);
dropbear_assert(ses.decryptreadbuf == NULL);
ses.decryptreadbuf = buf_new(blocksize);
} }
maxlen = blocksize - ses.readbuf->pos; maxlen = blocksize - ses.readbuf->pos;
@ -180,7 +181,7 @@ static void read_packet_init() {
if (len < 0) { if (len < 0) {
if (errno == EINTR) { if (errno == EINTR) {
TRACE(("leave read_packet_init: EINTR")) TRACE(("leave read_packet_init: EINTR"))
return; return DROPBEAR_FAILURE;
} }
dropbear_exit("error reading: %s", strerror(errno)); dropbear_exit("error reading: %s", strerror(errno));
} }
@ -189,22 +190,22 @@ static void read_packet_init() {
if ((unsigned int)len != maxlen) { if ((unsigned int)len != maxlen) {
/* don't have enough bytes to determine length, get next time */ /* don't have enough bytes to determine length, get next time */
return; return DROPBEAR_FAILURE;
} }
/* now we have the first block, need to get packet length, so we decrypt /* now we have the first block, need to get packet length, so we decrypt
* the first block (only need first 4 bytes) */ * the first block (only need first 4 bytes) */
buf_setpos(ses.readbuf, 0); buf_setpos(ses.readbuf, 0);
if (ses.keys->recv_crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
buf_getwriteptr(ses.decryptreadbuf,blocksize), buf_getwriteptr(ses.readbuf, blocksize),
blocksize, blocksize,
&ses.keys->recv_cipher_state) != CRYPT_OK) { &ses.keys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("error decrypting"); dropbear_exit("error decrypting");
} }
buf_setlen(ses.decryptreadbuf, blocksize); len = buf_getint(ses.readbuf) + 4 + macsize;
len = buf_getint(ses.decryptreadbuf) + 4 + macsize;
TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
buf_setpos(ses.readbuf, blocksize);
/* check packet length */ /* check packet length */
if ((len > RECV_MAX_PACKET_LEN) || if ((len > RECV_MAX_PACKET_LEN) ||
@ -213,9 +214,12 @@ static void read_packet_init() {
dropbear_exit("bad packet size %d", len); dropbear_exit("bad packet size %d", len);
} }
buf_resize(ses.readbuf, len); if (len > ses.readbuf->size) {
buf_resize(ses.readbuf, len);
}
buf_setlen(ses.readbuf, len); buf_setlen(ses.readbuf, len);
buf_setpos(ses.readbuf, blocksize);
return DROPBEAR_SUCCESS;
} }
/* handle the received packet */ /* handle the received packet */
@ -227,68 +231,60 @@ void decrypt_packet() {
unsigned int len; unsigned int len;
TRACE(("enter decrypt_packet")) TRACE(("enter decrypt_packet"))
blocksize = ses.keys->recv_algo_crypt->blocksize; blocksize = ses.keys->recv.algo_crypt->blocksize;
macsize = ses.keys->recv_algo_mac->hashsize; macsize = ses.keys->recv.algo_mac->hashsize;
ses.kexstate.datarecv += ses.readbuf->len; ses.kexstate.datarecv += ses.readbuf->len;
/* we've already decrypted the first blocksize in read_packet_init */ /* we've already decrypted the first blocksize in read_packet_init */
buf_setpos(ses.readbuf, blocksize); buf_setpos(ses.readbuf, blocksize);
buf_resize(ses.decryptreadbuf, ses.readbuf->len - macsize); /* decrypt it in-place */
buf_setlen(ses.decryptreadbuf, ses.decryptreadbuf->size);
buf_setpos(ses.decryptreadbuf, blocksize);
/* decrypt it */
len = ses.readbuf->len - macsize - ses.readbuf->pos; len = ses.readbuf->len - macsize - ses.readbuf->pos;
if (ses.keys->recv_crypt_mode->decrypt( if (ses.keys->recv.crypt_mode->decrypt(
buf_getptr(ses.readbuf, len), buf_getptr(ses.readbuf, len),
buf_getwriteptr(ses.decryptreadbuf, len), buf_getwriteptr(ses.readbuf, len),
len, len,
&ses.keys->recv_cipher_state) != CRYPT_OK) { &ses.keys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("error decrypting"); dropbear_exit("error decrypting");
} }
buf_incrpos(ses.readbuf, len); buf_incrpos(ses.readbuf, len);
buf_incrwritepos(ses.decryptreadbuf, len);
printhex("readbuf decrypted", ses.readbuf->data, ses.readbuf->len);
/* check the hmac */ /* check the hmac */
buf_setpos(ses.readbuf, ses.readbuf->len - macsize); if (checkmac() != DROPBEAR_SUCCESS) {
if (checkmac(ses.readbuf, ses.decryptreadbuf) != DROPBEAR_SUCCESS) {
dropbear_exit("Integrity error"); dropbear_exit("Integrity error");
} }
/* readbuf no longer required */
buf_free(ses.readbuf);
ses.readbuf = NULL;
/* get padding length */ /* get padding length */
buf_setpos(ses.decryptreadbuf, PACKET_PADDING_OFF); buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
padlen = buf_getbyte(ses.decryptreadbuf); padlen = buf_getbyte(ses.readbuf);
/* payload length */ /* payload length */
/* - 4 - 1 is for LEN and PADLEN values */ /* - 4 - 1 is for LEN and PADLEN values */
len = ses.decryptreadbuf->len - padlen - 4 - 1; len = ses.readbuf->len - padlen - 4 - 1;
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) { if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
dropbear_exit("bad packet size"); dropbear_exit("bad packet size");
} }
buf_setpos(ses.decryptreadbuf, PACKET_PAYLOAD_OFF); buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
if (is_compress_recv()) { if (is_compress_recv()) {
/* decompress */ /* decompress */
ses.payload = buf_decompress(ses.decryptreadbuf, len); ses.payload = buf_decompress(ses.readbuf, len);
} else } else
#endif #endif
{ {
/* copy payload */ /* copy payload */
ses.payload = buf_new(len); ses.payload = buf_new(len);
memcpy(ses.payload->data, buf_getptr(ses.decryptreadbuf, len), len); memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
buf_incrlen(ses.payload, len); buf_incrlen(ses.payload, len);
} }
buf_free(ses.decryptreadbuf); buf_free(ses.readbuf);
ses.decryptreadbuf = NULL; ses.readbuf = NULL;
buf_setpos(ses.payload, 0); buf_setpos(ses.payload, 0);
ses.recvseq++; ses.recvseq++;
@ -296,49 +292,22 @@ void decrypt_packet() {
TRACE(("leave decrypt_packet")) TRACE(("leave decrypt_packet"))
} }
/* Checks the mac in hashbuf, for the data in readbuf. /* Checks the mac at the end of a decrypted readbuf.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int checkmac(buffer* macbuf, buffer* sourcebuf) { static int checkmac() {
unsigned int macsize; unsigned char mac_bytes[MAX_MAC_LEN];
hmac_state hmac; unsigned int mac_size, contents_len;
unsigned char tempbuf[MAX_MAC_LEN];
unsigned long bufsize;
unsigned int len;
macsize = ses.keys->recv_algo_mac->hashsize; mac_size = ses.keys->trans.algo_mac->hashsize;
if (macsize == 0) { contents_len = ses.readbuf->len - mac_size;
return DROPBEAR_SUCCESS;
}
/* calculate the mac */ buf_setpos(ses.readbuf, 0);
if (hmac_init(&hmac, make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
find_hash(ses.keys->recv_algo_mac->hashdesc->name),
ses.keys->recvmackey,
ses.keys->recv_algo_mac->keysize)
!= CRYPT_OK) {
dropbear_exit("HMAC error");
}
/* sequence number */
STORE32H(ses.recvseq, tempbuf);
if (hmac_process(&hmac, tempbuf, 4) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
buf_setpos(sourcebuf, 0);
len = sourcebuf->len;
if (hmac_process(&hmac, buf_getptr(sourcebuf, len), len) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
bufsize = sizeof(tempbuf);
if (hmac_done(&hmac, tempbuf, &bufsize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
/* compare the hash */ /* compare the hash */
if (memcmp(tempbuf, buf_getptr(macbuf, macsize), macsize) != 0) { buf_setpos(ses.readbuf, contents_len);
if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} else { } else {
return DROPBEAR_SUCCESS; return DROPBEAR_SUCCESS;
@ -353,7 +322,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
buffer * ret; buffer * ret;
z_streamp zstream; z_streamp zstream;
zstream = ses.keys->recv_zstream; zstream = ses.keys->recv.zstream;
ret = buf_new(len); ret = buf_new(len);
zstream->avail_in = len; zstream->avail_in = len;
@ -468,8 +437,8 @@ void encrypt_packet() {
return; return;
} }
blocksize = ses.keys->trans_algo_crypt->blocksize; blocksize = ses.keys->trans.algo_crypt->blocksize;
mac_size = ses.keys->trans_algo_mac->hashsize; mac_size = ses.keys->trans.algo_mac->hashsize;
/* Encrypted packet len is payload+5, then worst case is if we are 3 away /* Encrypted packet len is payload+5, then worst case is if we are 3 away
* from a blocksize multiple. In which case we need to pad to the * from a blocksize multiple. In which case we need to pad to the
@ -526,17 +495,17 @@ void encrypt_packet() {
buf_incrlen(writebuf, padlen); buf_incrlen(writebuf, padlen);
genrandom(buf_getptr(writebuf, padlen), padlen); genrandom(buf_getptr(writebuf, padlen), padlen);
make_mac(writebuf, mac_bytes); make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
/* do the actual encryption, in-place */ /* do the actual encryption, in-place */
buf_setpos(writebuf, 0); buf_setpos(writebuf, 0);
/* encrypt it in-place*/ /* encrypt it in-place*/
len = writebuf->len; len = writebuf->len;
if (ses.keys->trans_crypt_mode->encrypt( if (ses.keys->trans.crypt_mode->encrypt(
buf_getptr(writebuf, len), buf_getptr(writebuf, len),
buf_getwriteptr(writebuf, len), buf_getwriteptr(writebuf, len),
len, len,
&ses.keys->trans_cipher_state) != CRYPT_OK) { &ses.keys->trans.cipher_state) != CRYPT_OK) {
dropbear_exit("error encrypting"); dropbear_exit("error encrypting");
} }
buf_incrpos(writebuf, len); buf_incrpos(writebuf, len);
@ -557,35 +526,36 @@ void encrypt_packet() {
/* Create the packet mac, and append H(seqno|clearbuf) to the output */ /* Create the packet mac, and append H(seqno|clearbuf) to the output */
/* output_mac must have ses.keys->trans_algo_mac->hashsize bytes. */ /* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
static void make_mac(buffer * clearwritebuf, unsigned char *output_mac) { static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
buffer * clear_buf, unsigned int clear_len,
unsigned char *output_mac) {
unsigned char seqbuf[4]; unsigned char seqbuf[4];
unsigned long bufsize; unsigned long bufsize;
hmac_state hmac; hmac_state hmac;
TRACE(("enter writemac")) TRACE(("enter writemac"))
if (ses.keys->trans_algo_mac->hashsize > 0) { if (key_state->algo_mac->hashsize > 0) {
/* calculate the mac */ /* calculate the mac */
if (hmac_init(&hmac, if (hmac_init(&hmac,
find_hash(ses.keys->trans_algo_mac->hashdesc->name), key_state->hash_index,
ses.keys->transmackey, key_state->mackey,
ses.keys->trans_algo_mac->keysize) != CRYPT_OK) { key_state->algo_mac->keysize) != CRYPT_OK) {
dropbear_exit("HMAC error"); dropbear_exit("HMAC error");
} }
/* sequence number */ /* sequence number */
STORE32H(ses.transseq, seqbuf); STORE32H(seqno, seqbuf);
if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) { if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
dropbear_exit("HMAC error"); dropbear_exit("HMAC error");
} }
/* the actual contents */ /* the actual contents */
buf_setpos(clearwritebuf, 0); buf_setpos(clear_buf, 0);
if (hmac_process(&hmac, if (hmac_process(&hmac,
buf_getptr(clearwritebuf, buf_getptr(clear_buf, clear_len),
clearwritebuf->len), clear_len) != CRYPT_OK) {
clearwritebuf->len) != CRYPT_OK) {
dropbear_exit("HMAC error"); dropbear_exit("HMAC error");
} }
@ -609,29 +579,29 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
while (1) { while (1) {
ses.keys->trans_zstream->avail_in = endpos - src->pos; ses.keys->trans.zstream->avail_in = endpos - src->pos;
ses.keys->trans_zstream->next_in = ses.keys->trans.zstream->next_in =
buf_getptr(src, ses.keys->trans_zstream->avail_in); buf_getptr(src, ses.keys->trans.zstream->avail_in);
ses.keys->trans_zstream->avail_out = dest->size - dest->pos; ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
ses.keys->trans_zstream->next_out = ses.keys->trans.zstream->next_out =
buf_getwriteptr(dest, ses.keys->trans_zstream->avail_out); buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
result = deflate(ses.keys->trans_zstream, Z_SYNC_FLUSH); result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
buf_setpos(src, endpos - ses.keys->trans_zstream->avail_in); buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
buf_setlen(dest, dest->size - ses.keys->trans_zstream->avail_out); buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
buf_setpos(dest, dest->len); buf_setpos(dest, dest->len);
if (result != Z_OK) { if (result != Z_OK) {
dropbear_exit("zlib error"); dropbear_exit("zlib error");
} }
if (ses.keys->trans_zstream->avail_in == 0) { if (ses.keys->trans.zstream->avail_in == 0) {
break; break;
} }
dropbear_assert(ses.keys->trans_zstream->avail_out == 0); dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
/* the buffer has been filled, we must extend. This only happens in /* the buffer has been filled, we must extend. This only happens in
* unusual circumstances where the data grows in size after deflate(), * unusual circumstances where the data grows in size after deflate(),

View File

@ -44,6 +44,6 @@ typedef struct PacketType {
#define PACKET_PADDING_OFF 4 #define PACKET_PADDING_OFF 4
#define PACKET_PAYLOAD_OFF 5 #define PACKET_PAYLOAD_OFF 5
#define INIT_READBUF 200 #define INIT_READBUF 128
#endif /* _PACKET_H_ */ #endif /* _PACKET_H_ */

View File

@ -60,42 +60,36 @@ void cli_session(int sock_in, int sock_out, char *remotehost);
void cli_session_cleanup(); void cli_session_cleanup();
void cleantext(unsigned char* dirtytext); void cleantext(unsigned char* dirtytext);
struct key_context { /* crypto parameters that are stored individually for transmit and receive */
struct key_context_directional {
const struct dropbear_cipher *recv_algo_crypt; /* NULL for none */ const struct dropbear_cipher *algo_crypt; /* NULL for none */
const struct dropbear_cipher *trans_algo_crypt; /* NULL for none */ const struct dropbear_cipher_mode *crypt_mode;
const struct dropbear_cipher_mode *recv_crypt_mode; const struct dropbear_hash *algo_mac; /* NULL for none */
const struct dropbear_cipher_mode *trans_crypt_mode; int hash_index; /* lookup for libtomcrypt */
const struct dropbear_hash *recv_algo_mac; /* NULL for none */ char algo_comp; /* compression */
const struct dropbear_hash *trans_algo_mac; /* NULL for none */
char algo_kex;
char algo_hostkey;
char recv_algo_comp; /* compression */
char trans_algo_comp;
int allow_compress; /* whether compression has started (useful in
zlib@openssh.com delayed compression case) */
#ifndef DISABLE_ZLIB #ifndef DISABLE_ZLIB
z_streamp recv_zstream; z_streamp zstream;
z_streamp trans_zstream;
#endif #endif
/* actual keys */ /* actual keys */
union { union {
symmetric_CBC cbc; symmetric_CBC cbc;
#ifdef DROPBEAR_ENABLE_CTR_MODE #ifdef DROPBEAR_ENABLE_CTR_MODE
symmetric_CTR ctr; symmetric_CTR ctr;
#endif #endif
} recv_cipher_state; } cipher_state;
union { unsigned char mackey[MAX_MAC_KEY];
symmetric_CBC cbc; };
#ifdef DROPBEAR_ENABLE_CTR_MODE
symmetric_CTR ctr;
#endif
} trans_cipher_state;
unsigned char recvmackey[MAX_MAC_KEY];
unsigned char transmackey[MAX_MAC_KEY];
struct key_context {
struct key_context_directional recv;
struct key_context_directional trans;
char algo_kex;
char algo_hostkey;
int allow_compress; /* whether compression has started (useful in
zlib@openssh.com delayed compression case) */
}; };
struct packetlist; struct packetlist;
@ -128,8 +122,7 @@ struct sshsession {
throughout the code, as handlers fill out this throughout the code, as handlers fill out this
buffer with the packet to send. */ buffer with the packet to send. */
struct Queue writequeue; /* A queue of encrypted packets to send */ struct Queue writequeue; /* A queue of encrypted packets to send */
buffer *readbuf; /* Encrypted */ buffer *readbuf; /* From the wire, decrypted in-place */
buffer *decryptreadbuf; /* Post-decryption */
buffer *payload; /* Post-decompression, the actual SSH packet */ buffer *payload; /* Post-decompression, the actual SSH packet */
unsigned int transseq, recvseq; /* Sequence IDs */ unsigned int transseq, recvseq; /* Sequence IDs */