123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- /*
- * Dropbear - a SSH2 server
- *
- * Copyright (c) 2002,2003 Matt Johnston
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE. */
- #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);
- /* For exact details see http://www.zlib.net/zlib_tech.html
- * 5 bytes per 16kB block, plus 6 bytes for the stream.
- * We might allocate 5 unnecessary bytes here if it's an
- * exact multiple. */
- #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
- /* non-blocking function writing out a current encrypted packet */
- void write_packet() {
- ssize_t written;
- #if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
- /* 50 is somewhat arbitrary */
- 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);
- /* This may return EAGAIN. The main loop sometimes
- calls write_packet() without bothering to test with select() since
- it's likely to be necessary */
- #if DROPBEAR_FUZZ
- if (fuzz.fuzzing) {
- /* pretend to write one packet at a time */
- /* TODO(fuzz): randomise amount written based on the fuzz input */
- 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 /* No writev () */
- #if DROPBEAR_FUZZ
- _Static_assert(0, "No fuzzing code for no-writev writes");
- #endif
- /* Get the next buffer in the queue of encrypted packets to write*/
- writebuf = (buffer*)examine(&ses.writequeue);
- len = writebuf->len - writebuf->pos;
- dropbear_assert(len > 0);
- /* Try to write as much as possible */
- 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) {
- /* We've finished with the packet, free it */
- dequeue(&ses.writequeue);
- buf_free(writebuf);
- writebuf = NULL;
- } else {
- /* More packet left to write, leave it in the queue for later */
- buf_incrpos(writebuf, written);
- }
- #endif /* writev */
- TRACE2(("leave write_packet"))
- }
- /* Non-blocking function reading available portion of a packet into the
- * ses's buffer, decrypting the length if encrypted, decrypting the
- * full portion if possible */
- 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;
- /* In the first blocksize of a packet */
- /* Read the first blocksize of the packet, so we can decrypt it and
- * find the length of the whole packet */
- ret = read_packet_init();
- if (ret == DROPBEAR_FAILURE) {
- /* didn't read enough to determine the length */
- TRACE2(("leave read_packet: packetinit done"))
- return;
- }
- }
- /* Attempt to read the remainder of the packet, note that there
- * mightn't be any available (EAGAIN) */
- maxlen = ses.readbuf->len - ses.readbuf->pos;
- if (maxlen == 0) {
- /* Occurs when the packet is only a single block long and has all
- * been read in read_packet_init(). Usually means that MAC is disabled
- */
- 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) {
- /* The whole packet has been read */
- decrypt_packet();
- /* The main select() loop process_packet() to
- * handle the packet contents... */
- }
- TRACE2(("leave read_packet"))
- }
- /* Function used to read the initial portion of a packet, and determine the
- * length. Only called during the first BLOCKSIZE of a packet. */
- /* Returns DROPBEAR_SUCCESS if the length is determined,
- * DROPBEAR_FAILURE otherwise */
- 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) {
- /* start of a new packet */
- ses.readbuf = buf_new(INIT_READBUF);
- }
- maxlen = blocksize - ses.readbuf->pos;
-
- /* read the rest of the packet if possible */
- 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) {
- /* don't have enough bytes to determine length, get next time */
- return DROPBEAR_FAILURE;
- }
- /* now we have the first block, need to get packet length, so we decrypt
- * the first block (only need first 4 bytes) */
- 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))
- /* check packet length */
- 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;
- }
- /* handle the received packet */
- 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) {
- /* first blocksize is not decrypted yet */
- buf_setpos(ses.readbuf, 0);
- /* decrypt it in-place */
- 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
- {
- /* we've already decrypted the first blocksize in read_packet_init */
- buf_setpos(ses.readbuf, blocksize);
- /* decrypt it in-place */
- 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);
- /* check the hmac */
- if (checkmac() != DROPBEAR_SUCCESS) {
- dropbear_exit("Integrity error");
- }
- }
-
- #if DROPBEAR_FUZZ
- fuzz_dump(ses.readbuf->data, ses.readbuf->len);
- #endif
- /* get padding length */
- buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
- padlen = buf_getbyte(ses.readbuf);
-
- /* payload length */
- /* - 4 - 1 is for LEN and PADLEN values */
- 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()) {
- /* decompress */
- 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"))
- }
- /* Checks the mac at the end of a decrypted readbuf.
- * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
- 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) {
- /* fail 1 in 2000 times to test error path. */
- 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
- /* compare the hash */
- 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
- /* returns a pointer to a newly created buffer */
- 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);
- /* decompress the payload, incrementally resizing the output buffer */
- 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)) {
- /* we can only exit if avail_out hasn't all been used,
- * and there's no remaining input */
- return ret;
- }
- if (zstream->avail_out == 0) {
- int new_size = 0;
- if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
- /* Already been increased as large as it can go,
- * yet didn't finish up the decompression */
- 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
- /* returns 1 if the packet is a valid type during kex (see 7.1 of rfc4253) */
- 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) {
- /* XXX should this die horribly if !dataallowed ?? */
- 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;
- }
-
- /* encrypt the writepayload, putting into writebuf, ready for write_packet()
- * to put on the wire */
- void encrypt_packet() {
- unsigned char padlen;
- unsigned char blocksize, mac_size;
- buffer * writebuf; /* the packet which will go on the wire. This is
- encrypted in-place. */
- 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))) {
- /* During key exchange only particular packets are allowed.
- Since this packet_type isn't OK we just enqueue it to send
- after the KEX, see maybe_flush_reply_queue */
- enqueue_reply_packet();
- return;
- }
-
- blocksize = ses.keys->trans.algo_crypt->blocksize;
- mac_size = ses.keys->trans.algo_mac->hashsize;
- /* Encrypted packet len is payload+5. We need to then make sure
- * there is enough space for padding or MIN_PACKET_LEN.
- * Add extra 3 since we need at least 4 bytes of padding */
- encrypt_buf_size = (ses.writepayload->len+4+1)
- + MAX(MIN_PACKET_LEN, blocksize) + 3
- /* add space for the MAC at the end */
- + mac_size
- #ifndef DISABLE_ZLIB
- /* some extra in case 'compression' makes it larger */
- + ZLIB_COMPRESS_EXPANSION
- #endif
- /* and an extra cleartext (stripped before transmission) byte for the
- * packet type */
- + 1;
- writebuf = buf_new(encrypt_buf_size);
- buf_setlen(writebuf, PACKET_PAYLOAD_OFF);
- buf_setpos(writebuf, PACKET_PAYLOAD_OFF);
- #ifndef DISABLE_ZLIB
- /* compression */
- 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);
- }
- /* finished with payload */
- buf_setpos(ses.writepayload, 0);
- buf_setlen(ses.writepayload, 0);
- /* length of padding - packet length excluding the packetlength uint32
- * field in aead mode must be a multiple of blocksize, with a minimum of
- * 4 bytes of padding */
- 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;
- }
- /* check for min packet length */
- if (writebuf->len + padlen < MIN_PACKET_LEN) {
- padlen += blocksize;
- }
- buf_setpos(writebuf, 0);
- /* packet length excluding the packetlength uint32 */
- buf_putint(writebuf, writebuf->len + padlen - 4);
- /* padding len */
- buf_putbyte(writebuf, padlen);
- /* actual padding */
- 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) {
- /* do the actual encryption, in-place */
- buf_setpos(writebuf, 0);
- /* encrypt it in-place*/
- 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);
- /* do the actual encryption, in-place */
- buf_setpos(writebuf, 0);
- /* encrypt it in-place*/
- 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);
- /* stick the MAC on it */
- buf_putbytes(writebuf, mac_bytes, mac_size);
- }
- /* Update counts */
- ses.kexstate.datatrans += writebuf->len;
- writebuf_enqueue(writebuf);
- /* Update counts */
- ses.transseq++;
- now = monotonic_now();
- ses.last_packet_time_any_sent = now;
- /* idle timeout shouldn't be affected by responses to keepalives.
- send_msg_keepalive() itself also does tricks with
- ses.last_packet_idle_time - read that if modifying this code */
- 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) {
- /* enqueue the packet for sending. It will get freed after transmission. */
- buf_setpos(writebuf, 0);
- enqueue(&ses.writequeue, (void*)writebuf);
- ses.writequeue_len += writebuf->len;
- }
- /* Create the packet mac, and append H(seqno|clearbuf) to the output */
- /* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
- 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) {
- /* calculate the mac */
- if (hmac_init(&hmac,
- key_state->hash_index,
- key_state->mackey,
- key_state->algo_mac->keysize) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
-
- /* sequence number */
- STORE32H(seqno, seqbuf);
- if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
-
- /* the actual contents */
- 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
- /* compresses len bytes from src, outputting to dest (starting from the
- * respective current positions. dest must have sufficient space,
- * len+ZLIB_COMPRESS_EXPANSION */
- 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");
- }
- /* fails if destination buffer wasn't large enough */
- dropbear_assert(ses.keys->trans.zstream->avail_in == 0);
- TRACE2(("leave buf_compress"))
- }
- #endif
|