123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- #include "includes.h"
- #include "packet.h"
- #include "session.h"
- #include "dbutil.h"
- #include "ssh.h"
- #include "algo.h"
- #include "buffer.h"
- #include "kex.h"
- #include "dbrandom.h"
- #include "service.h"
- #include "auth.h"
- #include "channel.h"
- #include "netio.h"
- #include "runopts.h"
- static int read_packet_init(void);
- 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);
- static int checkmac(void);
- #define ZLIB_COMPRESS_EXPANSION (((RECV_MAX_PAYLOAD_LEN/16384)+1)*5 + 6)
- #define ZLIB_DECOMPRESS_INCR 1024
- #ifndef DISABLE_ZLIB
- static buffer* buf_decompress(const buffer* buf, unsigned int len);
- static void buf_compress(buffer * dest, buffer * src, unsigned int len);
- #endif
- void write_packet() {
- ssize_t written;
- #if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
-
- unsigned int iov_count = 50;
- struct iovec iov[50];
- #else
- int len;
- buffer* writebuf;
- #endif
-
- TRACE2(("enter write_packet"))
- dropbear_assert(!isempty(&ses.writequeue));
- #if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
- packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
-
- #if DROPBEAR_FUZZ
- if (fuzz.fuzzing) {
-
-
- written = iov[0].iov_len;
- }
- else
- #endif
- {
- written = writev(ses.sock_out, iov, iov_count);
- if (written < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- TRACE2(("leave write_packet: EINTR"))
- return;
- } else {
- dropbear_exit("Error writing: %s", strerror(errno));
- }
- }
- }
- packet_queue_consume(&ses.writequeue, written);
- ses.writequeue_len -= written;
- if (written == 0) {
- ses.remoteclosed();
- }
- #else
- #if DROPBEAR_FUZZ
- _Static_assert(0, "No fuzzing code for no-writev writes");
- #endif
-
- writebuf = (buffer*)examine(&ses.writequeue);
- len = writebuf->len - writebuf->pos;
- dropbear_assert(len > 0);
-
- written = write(ses.sock_out, buf_getptr(writebuf, len), len);
- if (written < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- TRACE2(("leave writepacket: EINTR"))
- return;
- } else {
- dropbear_exit("Error writing: %s", strerror(errno));
- }
- }
- if (written == 0) {
- ses.remoteclosed();
- }
- ses.writequeue_len -= written;
- if (written == len) {
-
- dequeue(&ses.writequeue);
- buf_free(writebuf);
- writebuf = NULL;
- } else {
-
- buf_incrpos(writebuf, written);
- }
- #endif
- TRACE2(("leave write_packet"))
- }
- void read_packet() {
- int len;
- unsigned int maxlen;
- unsigned char blocksize;
- TRACE2(("enter read_packet"))
- blocksize = ses.keys->recv.algo_crypt->blocksize;
-
- if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
- int ret;
-
-
- ret = read_packet_init();
- if (ret == DROPBEAR_FAILURE) {
-
- TRACE2(("leave read_packet: packetinit done"))
- return;
- }
- }
-
- maxlen = ses.readbuf->len - ses.readbuf->pos;
- if (maxlen == 0) {
-
- len = 0;
- } else {
- len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
- if (len == 0) {
- ses.remoteclosed();
- }
- if (len < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- TRACE2(("leave read_packet: EINTR or EAGAIN"))
- return;
- } else {
- dropbear_exit("Error reading: %s", strerror(errno));
- }
- }
- buf_incrpos(ses.readbuf, len);
- }
- if ((unsigned int)len == maxlen) {
-
- decrypt_packet();
-
- }
- TRACE2(("leave read_packet"))
- }
- static int read_packet_init() {
- unsigned int maxlen;
- int slen;
- unsigned int len, plen;
- unsigned int blocksize;
- unsigned int macsize;
- blocksize = ses.keys->recv.algo_crypt->blocksize;
- macsize = ses.keys->recv.algo_mac->hashsize;
- if (ses.readbuf == NULL) {
-
- ses.readbuf = buf_new(INIT_READBUF);
- }
- maxlen = blocksize - ses.readbuf->pos;
-
-
- slen = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
- maxlen);
- if (slen == 0) {
- ses.remoteclosed();
- }
- if (slen < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- TRACE2(("leave read_packet_init: EINTR"))
- return DROPBEAR_FAILURE;
- }
- dropbear_exit("Error reading: %s", strerror(errno));
- }
- buf_incrwritepos(ses.readbuf, slen);
- if ((unsigned int)slen != maxlen) {
-
- return DROPBEAR_FAILURE;
- }
-
- buf_setpos(ses.readbuf, 0);
- #if DROPBEAR_AEAD_MODE
- if (ses.keys->recv.crypt_mode->aead_crypt) {
- if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq,
- buf_getptr(ses.readbuf, blocksize), &plen,
- blocksize,
- &ses.keys->recv.cipher_state) != CRYPT_OK) {
- dropbear_exit("Error decrypting");
- }
- len = plen + 4 + macsize;
- } else
- #endif
- {
- if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
- buf_getwriteptr(ses.readbuf, blocksize),
- blocksize,
- &ses.keys->recv.cipher_state) != CRYPT_OK) {
- dropbear_exit("Error decrypting");
- }
- plen = buf_getint(ses.readbuf) + 4;
- len = plen + macsize;
- }
- TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
-
- if ((len > RECV_MAX_PACKET_LEN) ||
- (plen < blocksize) ||
- (plen % blocksize != 0)) {
- dropbear_exit("Integrity error (bad packet size %u)", len);
- }
- if (len > ses.readbuf->size) {
- ses.readbuf = buf_resize(ses.readbuf, len);
- }
- buf_setlen(ses.readbuf, len);
- buf_setpos(ses.readbuf, blocksize);
- return DROPBEAR_SUCCESS;
- }
- void decrypt_packet() {
- unsigned char blocksize;
- unsigned char macsize;
- unsigned int padlen;
- unsigned int len;
- TRACE2(("enter decrypt_packet"))
- blocksize = ses.keys->recv.algo_crypt->blocksize;
- macsize = ses.keys->recv.algo_mac->hashsize;
- ses.kexstate.datarecv += ses.readbuf->len;
- #if DROPBEAR_AEAD_MODE
- if (ses.keys->recv.crypt_mode->aead_crypt) {
-
- buf_setpos(ses.readbuf, 0);
-
- len = ses.readbuf->len - macsize - ses.readbuf->pos;
- if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq,
- buf_getptr(ses.readbuf, len + macsize),
- buf_getwriteptr(ses.readbuf, len),
- len, macsize,
- &ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) {
- dropbear_exit("Error decrypting");
- }
- buf_incrpos(ses.readbuf, len);
- } else
- #endif
- {
-
- buf_setpos(ses.readbuf, blocksize);
-
- len = ses.readbuf->len - macsize - ses.readbuf->pos;
- if (ses.keys->recv.crypt_mode->decrypt(
- buf_getptr(ses.readbuf, len),
- buf_getwriteptr(ses.readbuf, len),
- len,
- &ses.keys->recv.cipher_state) != CRYPT_OK) {
- dropbear_exit("Error decrypting");
- }
- buf_incrpos(ses.readbuf, len);
-
- if (checkmac() != DROPBEAR_SUCCESS) {
- dropbear_exit("Integrity error");
- }
- }
-
- #if DROPBEAR_FUZZ
- fuzz_dump(ses.readbuf->data, ses.readbuf->len);
- #endif
-
- buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
- padlen = buf_getbyte(ses.readbuf);
-
-
-
- len = ses.readbuf->len - padlen - 4 - 1 - macsize;
- if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
- dropbear_exit("Bad packet size %u", len);
- }
- buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
- #ifndef DISABLE_ZLIB
- if (is_compress_recv()) {
-
- ses.payload = buf_decompress(ses.readbuf, len);
- buf_setpos(ses.payload, 0);
- ses.payload_beginning = 0;
- buf_free(ses.readbuf);
- } else
- #endif
- {
- ses.payload = ses.readbuf;
- ses.payload_beginning = ses.payload->pos;
- buf_setlen(ses.payload, ses.payload->pos + len);
- }
- ses.readbuf = NULL;
- ses.recvseq++;
- TRACE2(("leave decrypt_packet"))
- }
- static int checkmac() {
- unsigned char mac_bytes[MAX_MAC_LEN];
- unsigned int mac_size, contents_len;
-
- mac_size = ses.keys->recv.algo_mac->hashsize;
- contents_len = ses.readbuf->len - mac_size;
- buf_setpos(ses.readbuf, 0);
- make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
- #if DROPBEAR_FUZZ
- if (fuzz.fuzzing) {
-
- unsigned int value = 0;
- if (mac_size > sizeof(value)) {
- memcpy(&value, mac_bytes, sizeof(value));
- }
- if (value % 2000 == 99) {
- return DROPBEAR_FAILURE;
- }
- return DROPBEAR_SUCCESS;
- }
- #endif
-
- buf_setpos(ses.readbuf, contents_len);
- if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
- return DROPBEAR_FAILURE;
- } else {
- return DROPBEAR_SUCCESS;
- }
- }
- #ifndef DISABLE_ZLIB
- static buffer* buf_decompress(const buffer* buf, unsigned int len) {
- int result;
- buffer * ret;
- z_streamp zstream;
- zstream = ses.keys->recv.zstream;
- ret = buf_new(len);
- zstream->avail_in = len;
- zstream->next_in = buf_getptr(buf, len);
-
- while (1) {
- zstream->avail_out = ret->size - ret->pos;
- zstream->next_out = buf_getwriteptr(ret, zstream->avail_out);
- result = inflate(zstream, Z_SYNC_FLUSH);
- buf_setlen(ret, ret->size - zstream->avail_out);
- buf_setpos(ret, ret->len);
- if (result != Z_BUF_ERROR && result != Z_OK) {
- dropbear_exit("zlib error");
- }
- if (zstream->avail_in == 0 &&
- (zstream->avail_out != 0 || result == Z_BUF_ERROR)) {
-
- return ret;
- }
- if (zstream->avail_out == 0) {
- int new_size = 0;
- if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
-
- dropbear_exit("bad packet, oversized decompressed");
- }
- new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
- ret = buf_resize(ret, new_size);
- }
- }
- }
- #endif
- static int packet_is_okay_kex(unsigned char type) {
- if (type >= SSH_MSG_USERAUTH_REQUEST) {
- return 0;
- }
- if (type == SSH_MSG_SERVICE_REQUEST || type == SSH_MSG_SERVICE_ACCEPT) {
- return 0;
- }
- if (type == SSH_MSG_KEXINIT) {
-
- return 0;
- }
- return 1;
- }
- static void enqueue_reply_packet() {
- struct packetlist * new_item = NULL;
- new_item = m_malloc(sizeof(struct packetlist));
- new_item->next = NULL;
-
- new_item->payload = buf_newcopy(ses.writepayload);
- buf_setpos(ses.writepayload, 0);
- buf_setlen(ses.writepayload, 0);
-
- if (ses.reply_queue_tail) {
- ses.reply_queue_tail->next = new_item;
- } else {
- ses.reply_queue_head = new_item;
- }
- ses.reply_queue_tail = new_item;
- }
- void maybe_flush_reply_queue() {
- struct packetlist *tmp_item = NULL, *curr_item = NULL;
- if (!ses.dataallowed)
- {
- TRACE(("maybe_empty_reply_queue - no data allowed"))
- return;
- }
-
- for (curr_item = ses.reply_queue_head; curr_item; ) {
- CHECKCLEARTOWRITE();
- buf_putbytes(ses.writepayload,
- curr_item->payload->data, curr_item->payload->len);
-
- buf_free(curr_item->payload);
- tmp_item = curr_item;
- curr_item = curr_item->next;
- m_free(tmp_item);
- encrypt_packet();
- }
- ses.reply_queue_head = ses.reply_queue_tail = NULL;
- }
-
- void encrypt_packet() {
- unsigned char padlen;
- unsigned char blocksize, mac_size;
- buffer * writebuf;
- unsigned char packet_type;
- unsigned int len, encrypt_buf_size;
- unsigned char mac_bytes[MAX_MAC_LEN];
- time_t now;
-
- TRACE2(("enter encrypt_packet()"))
- buf_setpos(ses.writepayload, 0);
- packet_type = buf_getbyte(ses.writepayload);
- buf_setpos(ses.writepayload, 0);
- TRACE2(("encrypt_packet type is %d", packet_type))
-
- if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) {
-
- enqueue_reply_packet();
- return;
- }
-
- blocksize = ses.keys->trans.algo_crypt->blocksize;
- mac_size = ses.keys->trans.algo_mac->hashsize;
-
- encrypt_buf_size = (ses.writepayload->len+4+1)
- + MAX(MIN_PACKET_LEN, blocksize) + 3
-
- + mac_size
- #ifndef DISABLE_ZLIB
-
- + ZLIB_COMPRESS_EXPANSION
- #endif
-
- + 1;
- writebuf = buf_new(encrypt_buf_size);
- buf_setlen(writebuf, PACKET_PAYLOAD_OFF);
- buf_setpos(writebuf, PACKET_PAYLOAD_OFF);
- #ifndef DISABLE_ZLIB
-
- if (is_compress_trans()) {
- buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
- } else
- #endif
- {
- memcpy(buf_getwriteptr(writebuf, ses.writepayload->len),
- buf_getptr(ses.writepayload, ses.writepayload->len),
- ses.writepayload->len);
- buf_incrwritepos(writebuf, ses.writepayload->len);
- }
-
- buf_setpos(ses.writepayload, 0);
- buf_setlen(ses.writepayload, 0);
-
- len = writebuf->len;
- #if DROPBEAR_AEAD_MODE
- if (ses.keys->trans.crypt_mode->aead_crypt) {
- len -= 4;
- }
- #endif
- padlen = blocksize - len % blocksize;
- if (padlen < 4) {
- padlen += blocksize;
- }
-
- if (writebuf->len + padlen < MIN_PACKET_LEN) {
- padlen += blocksize;
- }
- buf_setpos(writebuf, 0);
-
- buf_putint(writebuf, writebuf->len + padlen - 4);
-
- buf_putbyte(writebuf, padlen);
-
- buf_setpos(writebuf, writebuf->len);
- buf_incrlen(writebuf, padlen);
- genrandom(buf_getptr(writebuf, padlen), padlen);
- #if DROPBEAR_AEAD_MODE
- if (ses.keys->trans.crypt_mode->aead_crypt) {
-
- buf_setpos(writebuf, 0);
-
- len = writebuf->len;
- buf_incrlen(writebuf, mac_size);
- if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq,
- buf_getptr(writebuf, len),
- buf_getwriteptr(writebuf, len + mac_size),
- len, mac_size,
- &ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) {
- dropbear_exit("Error encrypting");
- }
- buf_incrpos(writebuf, len + mac_size);
- } else
- #endif
- {
- make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
-
- buf_setpos(writebuf, 0);
-
- len = writebuf->len;
- if (ses.keys->trans.crypt_mode->encrypt(
- buf_getptr(writebuf, len),
- buf_getwriteptr(writebuf, len),
- len,
- &ses.keys->trans.cipher_state) != CRYPT_OK) {
- dropbear_exit("Error encrypting");
- }
- buf_incrpos(writebuf, len);
-
- buf_putbytes(writebuf, mac_bytes, mac_size);
- }
-
- ses.kexstate.datatrans += writebuf->len;
- writebuf_enqueue(writebuf);
-
- ses.transseq++;
- now = monotonic_now();
- ses.last_packet_time_any_sent = now;
-
- if (packet_type != SSH_MSG_REQUEST_FAILURE
- && packet_type != SSH_MSG_UNIMPLEMENTED
- && packet_type != SSH_MSG_IGNORE) {
- ses.last_packet_time_idle = now;
- }
- TRACE2(("leave encrypt_packet()"))
- }
- void writebuf_enqueue(buffer * writebuf) {
-
- buf_setpos(writebuf, 0);
- enqueue(&ses.writequeue, (void*)writebuf);
- ses.writequeue_len += writebuf->len;
- }
- 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 long bufsize;
- hmac_state hmac;
- if (key_state->algo_mac->hashsize > 0) {
-
- if (hmac_init(&hmac,
- key_state->hash_index,
- key_state->mackey,
- key_state->algo_mac->keysize) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
-
-
- STORE32H(seqno, seqbuf);
- if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
-
-
- buf_setpos(clear_buf, 0);
- if (hmac_process(&hmac,
- buf_getptr(clear_buf, clear_len),
- clear_len) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
-
- bufsize = MAX_MAC_LEN;
- if (hmac_done(&hmac, output_mac, &bufsize) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
- }
- TRACE2(("leave writemac"))
- }
- #ifndef DISABLE_ZLIB
- static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
- unsigned int endpos = src->pos + len;
- int result;
- TRACE2(("enter buf_compress"))
- dropbear_assert(dest->size - dest->pos >= len+ZLIB_COMPRESS_EXPANSION);
- ses.keys->trans.zstream->avail_in = endpos - src->pos;
- ses.keys->trans.zstream->next_in =
- buf_getptr(src, ses.keys->trans.zstream->avail_in);
- ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
- ses.keys->trans.zstream->next_out =
- buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
- result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
- buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
- buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
- buf_setpos(dest, dest->len);
- if (result != Z_OK) {
- dropbear_exit("zlib error");
- }
-
- dropbear_assert(ses.keys->trans.zstream->avail_in == 0);
- TRACE2(("leave buf_compress"))
- }
- #endif
|