Coverage Report

Created: 2025-10-13 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dropbear/src/packet.c
Line
Count
Source
1
/*
2
 * Dropbear - a SSH2 server
3
 * 
4
 * Copyright (c) 2002,2003 Matt Johnston
5
 * All rights reserved.
6
 * 
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 * 
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 * 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE. */
24
25
#include "includes.h"
26
#include "packet.h"
27
#include "session.h"
28
#include "dbutil.h"
29
#include "ssh.h"
30
#include "algo.h"
31
#include "buffer.h"
32
#include "kex.h"
33
#include "dbrandom.h"
34
#include "service.h"
35
#include "auth.h"
36
#include "channel.h"
37
#include "netio.h"
38
#include "runopts.h"
39
40
static int read_packet_init(void);
41
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
42
    buffer * clear_buf, unsigned int clear_len, 
43
    unsigned char *output_mac);
44
static int checkmac(void);
45
46
/* For exact details see http://www.zlib.net/zlib_tech.html
47
 * 5 bytes per 16kB block, plus 6 bytes for the stream.
48
 * We might allocate 5 unnecessary bytes here if it's an
49
 * exact multiple. */
50
32.4k
#define ZLIB_COMPRESS_EXPANSION (((RECV_MAX_PAYLOAD_LEN/16384)+1)*5 + 6)
51
#define ZLIB_DECOMPRESS_INCR 1024
52
#ifndef DISABLE_ZLIB
53
static buffer* buf_decompress(const buffer* buf, unsigned int len);
54
static void buf_compress(buffer * dest, buffer * src, unsigned int len);
55
#endif
56
57
/* non-blocking function writing out a current encrypted packet */
58
24.2k
void write_packet() {
59
60
24.2k
  ssize_t written;
61
24.2k
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
62
  /* 50 is somewhat arbitrary */
63
24.2k
  unsigned int iov_count = 50;
64
24.2k
  struct iovec iov[50];
65
#else
66
  int len;
67
  buffer* writebuf;
68
#endif
69
  
70
24.2k
  TRACE2(("enter write_packet"))
71
24.2k
  dropbear_assert(!isempty(&ses.writequeue));
72
73
24.2k
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
74
75
24.2k
  packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
76
  /* This may return EAGAIN. The main loop sometimes
77
  calls write_packet() without bothering to test with select() since
78
  it's likely to be necessary */
79
24.2k
#if DROPBEAR_FUZZ
80
24.2k
  if (fuzz.fuzzing) {
81
    /* pretend to write one packet at a time */
82
    /* TODO(fuzz): randomise amount written based on the fuzz input */
83
24.2k
    written = iov[0].iov_len;
84
24.2k
  }
85
0
  else
86
0
#endif
87
0
  {
88
0
  written = writev(ses.sock_out, iov, iov_count);
89
0
  if (written < 0) {
90
0
    if (errno == EINTR || errno == EAGAIN) {
91
0
      TRACE2(("leave write_packet: EINTR"))
92
0
      return;
93
0
    } else {
94
0
      dropbear_exit("Error writing: %s", strerror(errno));
95
0
    }
96
0
  }
97
0
  }
98
99
24.2k
  packet_queue_consume(&ses.writequeue, written);
100
24.2k
  ses.writequeue_len -= written;
101
102
24.2k
  if (written == 0) {
103
0
    ses.remoteclosed();
104
0
  }
105
106
#else /* No writev () */
107
#if DROPBEAR_FUZZ
108
  _Static_assert(0, "No fuzzing code for no-writev writes");
109
#endif
110
  /* Get the next buffer in the queue of encrypted packets to write*/
111
  writebuf = (buffer*)examine(&ses.writequeue);
112
113
  len = writebuf->len - writebuf->pos;
114
  dropbear_assert(len > 0);
115
  /* Try to write as much as possible */
116
  written = write(ses.sock_out, buf_getptr(writebuf, len), len);
117
118
  if (written < 0) {
119
    if (errno == EINTR || errno == EAGAIN) {
120
      TRACE2(("leave writepacket: EINTR"))
121
      return;
122
    } else {
123
      dropbear_exit("Error writing: %s", strerror(errno));
124
    }
125
  } 
126
127
  if (written == 0) {
128
    ses.remoteclosed();
129
  }
130
131
  ses.writequeue_len -= written;
132
133
  if (written == len) {
134
    /* We've finished with the packet, free it */
135
    dequeue(&ses.writequeue);
136
    buf_free(writebuf);
137
    writebuf = NULL;
138
  } else {
139
    /* More packet left to write, leave it in the queue for later */
140
    buf_incrpos(writebuf, written);
141
  }
142
#endif /* writev */
143
144
24.2k
  TRACE2(("leave write_packet"))
145
24.2k
}
146
147
/* Non-blocking function reading available portion of a packet into the
148
 * ses's buffer, decrypting the length if encrypted, decrypting the
149
 * full portion if possible */
150
124k
void read_packet() {
151
152
124k
  int len;
153
124k
  unsigned int maxlen;
154
124k
  unsigned char blocksize;
155
156
124k
  TRACE2(("enter read_packet"))
157
124k
  blocksize = ses.keys->recv.algo_crypt->blocksize;
158
  
159
124k
  if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
160
89.3k
    int ret;
161
    /* In the first blocksize of a packet */
162
163
    /* Read the first blocksize of the packet, so we can decrypt it and
164
     * find the length of the whole packet */
165
89.3k
    ret = read_packet_init();
166
167
89.3k
    if (ret == DROPBEAR_FAILURE) {
168
      /* didn't read enough to determine the length */
169
55.5k
      TRACE2(("leave read_packet: packetinit done"))
170
55.5k
      return;
171
55.5k
    }
172
89.3k
  }
173
174
  /* Attempt to read the remainder of the packet, note that there
175
   * mightn't be any available (EAGAIN) */
176
69.3k
  maxlen = ses.readbuf->len - ses.readbuf->pos;
177
69.3k
  if (maxlen == 0) {
178
    /* Occurs when the packet is only a single block long and has all
179
     * been read in read_packet_init().  Usually means that MAC is disabled
180
     */
181
18.6k
    len = 0;
182
50.7k
  } else {
183
50.7k
    len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
184
185
50.7k
    if (len == 0) {
186
117
      ses.remoteclosed();
187
117
    }
188
189
50.7k
    if (len < 0) {
190
67
      if (errno == EINTR || errno == EAGAIN) {
191
66
        TRACE2(("leave read_packet: EINTR or EAGAIN"))
192
66
        return;
193
66
      } else {
194
1
        dropbear_exit("Error reading: %s", strerror(errno));
195
1
      }
196
67
    }
197
198
50.6k
    buf_incrpos(ses.readbuf, len);
199
50.6k
  }
200
201
69.3k
  if ((unsigned int)len == maxlen) {
202
    /* The whole packet has been read */
203
32.4k
    decrypt_packet();
204
    /* The main select() loop process_packet() to
205
     * handle the packet contents... */
206
32.4k
  }
207
69.3k
  TRACE2(("leave read_packet"))
208
69.3k
}
209
210
/* Function used to read the initial portion of a packet, and determine the
211
 * length. Only called during the first BLOCKSIZE of a packet. */
212
/* Returns DROPBEAR_SUCCESS if the length is determined, 
213
 * DROPBEAR_FAILURE otherwise */
214
89.3k
static int read_packet_init() {
215
216
89.3k
  unsigned int maxlen;
217
89.3k
  int slen;
218
89.3k
  unsigned int len, plen;
219
89.3k
  unsigned int blocksize;
220
89.3k
  unsigned int macsize;
221
222
223
89.3k
  blocksize = ses.keys->recv.algo_crypt->blocksize;
224
89.3k
  macsize = ses.keys->recv.algo_mac->hashsize;
225
226
89.3k
  if (ses.readbuf == NULL) {
227
    /* start of a new packet */
228
33.7k
    ses.readbuf = buf_new(INIT_READBUF);
229
33.7k
  }
230
231
89.3k
  maxlen = blocksize - ses.readbuf->pos;
232
      
233
  /* read the rest of the packet if possible */
234
89.3k
  slen = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
235
89.3k
      maxlen);
236
89.3k
  if (slen == 0) {
237
1.11k
    ses.remoteclosed();
238
1.11k
  }
239
89.3k
  if (slen < 0) {
240
92
    if (errno == EINTR || errno == EAGAIN) {
241
89
      TRACE2(("leave read_packet_init: EINTR"))
242
89
      return DROPBEAR_FAILURE;
243
89
    }
244
3
    dropbear_exit("Error reading: %s", strerror(errno));
245
92
  }
246
247
89.2k
  buf_incrwritepos(ses.readbuf, slen);
248
249
89.2k
  if ((unsigned int)slen != maxlen) {
250
    /* don't have enough bytes to determine length, get next time */
251
55.4k
    return DROPBEAR_FAILURE;
252
55.4k
  }
253
254
  /* now we have the first block, need to get packet length, so we decrypt
255
   * the first block (only need first 4 bytes) */
256
33.7k
  buf_setpos(ses.readbuf, 0);
257
33.7k
#if DROPBEAR_AEAD_MODE
258
33.7k
  if (ses.keys->recv.crypt_mode->aead_crypt) {
259
0
    if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq,
260
0
          buf_getptr(ses.readbuf, blocksize), &plen,
261
0
          blocksize,
262
0
          &ses.keys->recv.cipher_state) != CRYPT_OK) {
263
0
      dropbear_exit("Error decrypting");
264
0
    }
265
0
    len = plen + 4 + macsize;
266
0
  } else
267
33.7k
#endif
268
33.7k
  {
269
33.7k
    if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), 
270
33.7k
          buf_getwriteptr(ses.readbuf, blocksize),
271
33.7k
          blocksize,
272
33.7k
          &ses.keys->recv.cipher_state) != CRYPT_OK) {
273
0
      dropbear_exit("Error decrypting");
274
0
    }
275
33.7k
    plen = buf_getint(ses.readbuf) + 4;
276
33.7k
    len = plen + macsize;
277
33.7k
  }
278
279
33.7k
  TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
280
281
282
  /* check packet length */
283
33.7k
  if ((len > RECV_MAX_PACKET_LEN) ||
284
32.6k
    (plen < blocksize) ||
285
32.6k
    (plen % blocksize != 0)) {
286
49
    dropbear_exit("Integrity error (bad packet size %u)", len);
287
49
  }
288
289
33.6k
  if (len > ses.readbuf->size) {
290
2.66k
    ses.readbuf = buf_resize(ses.readbuf, len);   
291
2.66k
  }
292
33.6k
  buf_setlen(ses.readbuf, len);
293
33.6k
  buf_setpos(ses.readbuf, blocksize);
294
33.6k
  return DROPBEAR_SUCCESS;
295
33.7k
}
296
297
/* handle the received packet */
298
32.4k
void decrypt_packet() {
299
300
32.4k
  unsigned char blocksize;
301
32.4k
  unsigned char macsize;
302
32.4k
  unsigned int padlen;
303
32.4k
  unsigned int len;
304
305
32.4k
  TRACE2(("enter decrypt_packet"))
306
32.4k
  blocksize = ses.keys->recv.algo_crypt->blocksize;
307
32.4k
  macsize = ses.keys->recv.algo_mac->hashsize;
308
309
32.4k
  ses.kexstate.datarecv += ses.readbuf->len;
310
311
32.4k
#if DROPBEAR_AEAD_MODE
312
32.4k
  if (ses.keys->recv.crypt_mode->aead_crypt) {
313
    /* first blocksize is not decrypted yet */
314
0
    buf_setpos(ses.readbuf, 0);
315
316
    /* decrypt it in-place */
317
0
    len = ses.readbuf->len - macsize - ses.readbuf->pos;
318
0
    if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq,
319
0
          buf_getptr(ses.readbuf, len + macsize),
320
0
          buf_getwriteptr(ses.readbuf, len),
321
0
          len, macsize,
322
0
          &ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) {
323
0
      dropbear_exit("Error decrypting");
324
0
    }
325
0
    buf_incrpos(ses.readbuf, len);
326
0
  } else
327
32.4k
#endif
328
32.4k
  {
329
    /* we've already decrypted the first blocksize in read_packet_init */
330
32.4k
    buf_setpos(ses.readbuf, blocksize);
331
332
    /* decrypt it in-place */
333
32.4k
    len = ses.readbuf->len - macsize - ses.readbuf->pos;
334
32.4k
    if (ses.keys->recv.crypt_mode->decrypt(
335
32.4k
          buf_getptr(ses.readbuf, len), 
336
32.4k
          buf_getwriteptr(ses.readbuf, len),
337
32.4k
          len,
338
32.4k
          &ses.keys->recv.cipher_state) != CRYPT_OK) {
339
0
      dropbear_exit("Error decrypting");
340
0
    }
341
32.4k
    buf_incrpos(ses.readbuf, len);
342
343
    /* check the hmac */
344
32.4k
    if (checkmac() != DROPBEAR_SUCCESS) {
345
0
      dropbear_exit("Integrity error");
346
0
    }
347
348
32.4k
  }
349
  
350
32.4k
#if DROPBEAR_FUZZ
351
32.4k
  fuzz_dump(ses.readbuf->data, ses.readbuf->len);
352
32.4k
#endif
353
354
  /* get padding length */
355
32.4k
  buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
356
32.4k
  padlen = buf_getbyte(ses.readbuf);
357
    
358
  /* payload length */
359
  /* - 4 - 1 is for LEN and PADLEN values */
360
32.4k
  len = ses.readbuf->len - padlen - 4 - 1 - macsize;
361
32.4k
  if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
362
13
    dropbear_exit("Bad packet size %u", len);
363
13
  }
364
365
32.4k
  buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
366
367
#ifndef DISABLE_ZLIB
368
  if (is_compress_recv()) {
369
    /* decompress */
370
    ses.payload = buf_decompress(ses.readbuf, len);
371
    buf_setpos(ses.payload, 0);
372
    ses.payload_beginning = 0;
373
    buf_free(ses.readbuf);
374
  } else 
375
#endif
376
32.4k
  {
377
32.4k
    ses.payload = ses.readbuf;
378
32.4k
    ses.payload_beginning = ses.payload->pos;
379
32.4k
    buf_setlen(ses.payload, ses.payload->pos + len);
380
32.4k
  }
381
32.4k
  ses.readbuf = NULL;
382
383
32.4k
  ses.recvseq++;
384
385
32.4k
  TRACE2(("leave decrypt_packet"))
386
32.4k
}
387
388
/* Checks the mac at the end of a decrypted readbuf.
389
 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
390
32.4k
static int checkmac() {
391
392
32.4k
  unsigned char mac_bytes[MAX_MAC_LEN];
393
32.4k
  unsigned int mac_size, contents_len;
394
  
395
32.4k
  mac_size = ses.keys->recv.algo_mac->hashsize;
396
32.4k
  contents_len = ses.readbuf->len - mac_size;
397
398
32.4k
  buf_setpos(ses.readbuf, 0);
399
32.4k
  make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
400
401
32.4k
#if DROPBEAR_FUZZ
402
32.4k
  if (fuzz.fuzzing) {
403
    /* fail 1 in 2000 times to test error path. */
404
32.4k
    unsigned int value = 0;
405
32.4k
    if (mac_size > sizeof(value)) {
406
0
      memcpy(&value, mac_bytes, sizeof(value));
407
0
    }
408
32.4k
    if (value % 2000 == 99) {
409
0
      return DROPBEAR_FAILURE;
410
0
    }
411
32.4k
    return DROPBEAR_SUCCESS;
412
32.4k
  }
413
0
#endif
414
415
  /* compare the hash */
416
0
  buf_setpos(ses.readbuf, contents_len);
417
0
  if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
418
0
    return DROPBEAR_FAILURE;
419
0
  } else {
420
0
    return DROPBEAR_SUCCESS;
421
0
  }
422
0
}
423
424
#ifndef DISABLE_ZLIB
425
/* returns a pointer to a newly created buffer */
426
static buffer* buf_decompress(const buffer* buf, unsigned int len) {
427
428
  int result;
429
  buffer * ret;
430
  z_streamp zstream;
431
432
  zstream = ses.keys->recv.zstream;
433
  /* We use RECV_MAX_PAYLOAD_LEN+1 here to ensure that
434
     we can detect an oversized payload after inflate() */
435
  ret = buf_new(RECV_MAX_PAYLOAD_LEN+1);
436
437
  zstream->avail_in = len;
438
  zstream->next_in = buf_getptr(buf, len);
439
  zstream->avail_out = ret->size;
440
  zstream->next_out = ret->data;
441
442
  result = inflate(zstream, Z_SYNC_FLUSH);
443
  if (result != Z_OK) {
444
    dropbear_exit("zlib error");
445
  }
446
447
  buf_setlen(ret, ret->size - zstream->avail_out);
448
449
  if (zstream->avail_in > 0 || ret->len > RECV_MAX_PAYLOAD_LEN) {
450
    /* The remote side sent larger than a payload size
451
     * of uncompressed data.
452
     */
453
    dropbear_exit("bad packet, oversized decompressed");
454
  }
455
456
  /* Success. All input was consumed and avail_out > 0 */
457
  return ret;
458
459
}
460
#endif
461
462
463
/* returns 1 if the packet is a valid type during kex (see 7.1 of rfc4253) */
464
22.3k
static int packet_is_okay_kex(unsigned char type) {
465
22.3k
  if (type >= SSH_MSG_USERAUTH_REQUEST) {
466
2.86k
    return 0;
467
2.86k
  }
468
19.5k
  if (type == SSH_MSG_SERVICE_REQUEST || type == SSH_MSG_SERVICE_ACCEPT) {
469
604
    return 0;
470
604
  }
471
18.9k
  if (type == SSH_MSG_KEXINIT) {
472
    /* XXX should this die horribly if !dataallowed ?? */
473
0
    return 0;
474
0
  }
475
18.9k
  return 1;
476
18.9k
}
477
478
3.46k
static void enqueue_reply_packet() {
479
3.46k
  struct packetlist * new_item = NULL;
480
3.46k
  new_item = m_malloc(sizeof(struct packetlist));
481
3.46k
  new_item->next = NULL;
482
  
483
3.46k
  new_item->payload = buf_newcopy(ses.writepayload);
484
3.46k
  buf_setpos(ses.writepayload, 0);
485
3.46k
  buf_setlen(ses.writepayload, 0);
486
  
487
3.46k
  if (ses.reply_queue_tail) {
488
2.65k
    ses.reply_queue_tail->next = new_item;
489
2.65k
  } else {
490
817
    ses.reply_queue_head = new_item;
491
817
  }
492
3.46k
  ses.reply_queue_tail = new_item;
493
3.46k
}
494
495
136k
void maybe_flush_reply_queue() {
496
136k
  struct packetlist *tmp_item = NULL, *curr_item = NULL;
497
136k
  if (!ses.dataallowed)
498
136k
  {
499
136k
    TRACE(("maybe_empty_reply_queue - no data allowed"))
500
136k
    return;
501
136k
  }
502
    
503
0
  for (curr_item = ses.reply_queue_head; curr_item; ) {
504
0
    CHECKCLEARTOWRITE();
505
0
    buf_putbytes(ses.writepayload,
506
0
      curr_item->payload->data, curr_item->payload->len);
507
      
508
0
    buf_free(curr_item->payload);
509
0
    tmp_item = curr_item;
510
0
    curr_item = curr_item->next;
511
0
    m_free(tmp_item);
512
0
    encrypt_packet();
513
0
  }
514
0
  ses.reply_queue_head = ses.reply_queue_tail = NULL;
515
0
}
516
  
517
/* encrypt the writepayload, putting into writebuf, ready for write_packet()
518
 * to put on the wire */
519
25.0k
void encrypt_packet() {
520
521
25.0k
  unsigned char padlen;
522
25.0k
  unsigned char blocksize, mac_size;
523
25.0k
  buffer * writebuf; /* the packet which will go on the wire. This is 
524
                        encrypted in-place. */
525
25.0k
  unsigned char packet_type;
526
25.0k
  unsigned int len, encrypt_buf_size;
527
25.0k
  unsigned char mac_bytes[MAX_MAC_LEN];
528
529
25.0k
  time_t now;
530
  
531
25.0k
  TRACE2(("enter encrypt_packet()"))
532
533
25.0k
  buf_setpos(ses.writepayload, 0);
534
25.0k
  packet_type = buf_getbyte(ses.writepayload);
535
25.0k
  buf_setpos(ses.writepayload, 0);
536
537
25.0k
  TRACE2(("encrypt_packet type is %d", packet_type))
538
  
539
25.0k
  if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) {
540
    /* During key exchange only particular packets are allowed.
541
      Since this packet_type isn't OK we just enqueue it to send 
542
      after the KEX, see maybe_flush_reply_queue */
543
3.46k
    enqueue_reply_packet();
544
3.46k
    return;
545
3.46k
  }
546
    
547
21.5k
  blocksize = ses.keys->trans.algo_crypt->blocksize;
548
21.5k
  mac_size = ses.keys->trans.algo_mac->hashsize;
549
550
  /* Encrypted packet len is payload+5. We need to then make sure
551
   * there is enough space for padding or MIN_PACKET_LEN. 
552
   * Add extra 3 since we need at least 4 bytes of padding */
553
21.5k
  encrypt_buf_size = (ses.writepayload->len+4+1) 
554
21.5k
    + MAX(MIN_PACKET_LEN, blocksize) + 3
555
  /* add space for the MAC at the end */
556
21.5k
        + mac_size
557
#ifndef DISABLE_ZLIB
558
  /* some extra in case 'compression' makes it larger */
559
        + ZLIB_COMPRESS_EXPANSION
560
#endif
561
  /* and an extra cleartext (stripped before transmission) byte for the
562
   * packet type */
563
21.5k
        + 1;
564
565
21.5k
  writebuf = buf_new(encrypt_buf_size);
566
21.5k
  buf_setlen(writebuf, PACKET_PAYLOAD_OFF);
567
21.5k
  buf_setpos(writebuf, PACKET_PAYLOAD_OFF);
568
569
#ifndef DISABLE_ZLIB
570
  /* compression */
571
  if (is_compress_trans()) {
572
    buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
573
  } else
574
#endif
575
21.5k
  {
576
21.5k
    memcpy(buf_getwriteptr(writebuf, ses.writepayload->len),
577
21.5k
        buf_getptr(ses.writepayload, ses.writepayload->len),
578
21.5k
        ses.writepayload->len);
579
21.5k
    buf_incrwritepos(writebuf, ses.writepayload->len);
580
21.5k
  }
581
582
  /* finished with payload */
583
21.5k
  buf_setpos(ses.writepayload, 0);
584
21.5k
  buf_setlen(ses.writepayload, 0);
585
586
  /* length of padding - packet length excluding the packetlength uint32
587
   * field in aead mode must be a multiple of blocksize, with a minimum of
588
   * 4 bytes of padding */
589
21.5k
  len = writebuf->len;
590
21.5k
#if DROPBEAR_AEAD_MODE
591
21.5k
  if (ses.keys->trans.crypt_mode->aead_crypt) {
592
0
    len -= 4;
593
0
  }
594
21.5k
#endif
595
21.5k
  padlen = blocksize - len % blocksize;
596
21.5k
  if (padlen < 4) {
597
0
    padlen += blocksize;
598
0
  }
599
  /* check for min packet length */
600
21.5k
  if (writebuf->len + padlen < MIN_PACKET_LEN) {
601
0
    padlen += blocksize;
602
0
  }
603
604
21.5k
  buf_setpos(writebuf, 0);
605
  /* packet length excluding the packetlength uint32 */
606
21.5k
  buf_putint(writebuf, writebuf->len + padlen - 4);
607
608
  /* padding len */
609
21.5k
  buf_putbyte(writebuf, padlen);
610
  /* actual padding */
611
21.5k
  buf_setpos(writebuf, writebuf->len);
612
21.5k
  buf_incrlen(writebuf, padlen);
613
21.5k
  genrandom(buf_getptr(writebuf, padlen), padlen);
614
615
21.5k
#if DROPBEAR_AEAD_MODE
616
21.5k
  if (ses.keys->trans.crypt_mode->aead_crypt) {
617
    /* do the actual encryption, in-place */
618
0
    buf_setpos(writebuf, 0);
619
    /* encrypt it in-place*/
620
0
    len = writebuf->len;
621
0
    buf_incrlen(writebuf, mac_size);
622
0
    if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq,
623
0
          buf_getptr(writebuf, len),
624
0
          buf_getwriteptr(writebuf, len + mac_size),
625
0
          len, mac_size,
626
0
          &ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) {
627
0
      dropbear_exit("Error encrypting");
628
0
    }
629
0
    buf_incrpos(writebuf, len + mac_size);
630
0
  } else
631
21.5k
#endif
632
21.5k
  {
633
21.5k
    make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
634
635
    /* do the actual encryption, in-place */
636
21.5k
    buf_setpos(writebuf, 0);
637
    /* encrypt it in-place*/
638
21.5k
    len = writebuf->len;
639
21.5k
    if (ses.keys->trans.crypt_mode->encrypt(
640
21.5k
          buf_getptr(writebuf, len),
641
21.5k
          buf_getwriteptr(writebuf, len),
642
21.5k
          len,
643
21.5k
          &ses.keys->trans.cipher_state) != CRYPT_OK) {
644
0
      dropbear_exit("Error encrypting");
645
0
    }
646
21.5k
    buf_incrpos(writebuf, len);
647
648
    /* stick the MAC on it */
649
21.5k
    buf_putbytes(writebuf, mac_bytes, mac_size);
650
21.5k
  }
651
652
  /* Update counts */
653
21.5k
  ses.kexstate.datatrans += writebuf->len;
654
655
21.5k
  writebuf_enqueue(writebuf);
656
657
  /* Update counts */
658
21.5k
  ses.transseq++;
659
660
21.5k
  now = monotonic_now();
661
21.5k
  ses.last_packet_time_any_sent = now;
662
  /* idle timeout shouldn't be affected by responses to keepalives.
663
  send_msg_keepalive() itself also does tricks with 
664
  ses.last_packet_idle_time - read that if modifying this code */
665
21.5k
  if (packet_type != SSH_MSG_REQUEST_FAILURE
666
21.5k
    && packet_type != SSH_MSG_UNIMPLEMENTED
667
2.66k
    && packet_type != SSH_MSG_IGNORE) {
668
2.66k
    ses.last_packet_time_idle = now;
669
670
2.66k
  }
671
672
21.5k
  TRACE2(("leave encrypt_packet()"))
673
21.5k
}
674
675
24.2k
void writebuf_enqueue(buffer * writebuf) {
676
  /* enqueue the packet for sending. It will get freed after transmission. */
677
24.2k
  buf_setpos(writebuf, 0);
678
24.2k
  enqueue(&ses.writequeue, (void*)writebuf);
679
24.2k
  ses.writequeue_len += writebuf->len;
680
24.2k
}
681
682
683
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
684
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
685
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
686
    buffer * clear_buf, unsigned int clear_len, 
687
54.0k
    unsigned char *output_mac) {
688
54.0k
  unsigned char seqbuf[4];
689
54.0k
  unsigned long bufsize;
690
54.0k
  hmac_state hmac;
691
692
54.0k
  if (key_state->algo_mac->hashsize > 0) {
693
    /* calculate the mac */
694
0
    if (hmac_init(&hmac, 
695
0
          key_state->hash_index,
696
0
          key_state->mackey,
697
0
          key_state->algo_mac->keysize) != CRYPT_OK) {
698
0
      dropbear_exit("HMAC error");
699
0
    }
700
  
701
    /* sequence number */
702
0
    STORE32H(seqno, seqbuf);
703
0
    if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
704
0
      dropbear_exit("HMAC error");
705
0
    }
706
  
707
    /* the actual contents */
708
0
    buf_setpos(clear_buf, 0);
709
0
    if (hmac_process(&hmac, 
710
0
          buf_getptr(clear_buf, clear_len),
711
0
          clear_len) != CRYPT_OK) {
712
0
      dropbear_exit("HMAC error");
713
0
    }
714
  
715
0
    bufsize = MAX_MAC_LEN;
716
0
    if (hmac_done(&hmac, output_mac, &bufsize) != CRYPT_OK) {
717
0
      dropbear_exit("HMAC error");
718
0
    }
719
0
  }
720
54.0k
  TRACE2(("leave writemac"))
721
54.0k
}
722
723
#ifndef DISABLE_ZLIB
724
/* compresses len bytes from src, outputting to dest (starting from the
725
 * respective current positions. dest must have sufficient space,
726
 * len+ZLIB_COMPRESS_EXPANSION */
727
static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
728
729
  unsigned int endpos = src->pos + len;
730
  int result;
731
732
  TRACE2(("enter buf_compress"))
733
734
  dropbear_assert(dest->size - dest->pos >= len+ZLIB_COMPRESS_EXPANSION);
735
736
  ses.keys->trans.zstream->avail_in = endpos - src->pos;
737
  ses.keys->trans.zstream->next_in = 
738
    buf_getptr(src, ses.keys->trans.zstream->avail_in);
739
740
  ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
741
  ses.keys->trans.zstream->next_out =
742
    buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
743
744
  result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
745
746
  buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
747
  buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
748
  buf_setpos(dest, dest->len);
749
750
  if (result != Z_OK) {
751
    dropbear_exit("zlib error");
752
  }
753
754
  /* fails if destination buffer wasn't large enough */
755
  dropbear_assert(ses.keys->trans.zstream->avail_in == 0);
756
  TRACE2(("leave buf_compress"))
757
}
758
#endif