ssh2bpp.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. * Binary packet protocol for SSH-2.
  3. */
  4. #include <assert.h>
  5. #include "putty.h"
  6. #include "ssh.h"
  7. #include "sshbpp.h"
  8. #include "sshcr.h"
  9. struct ssh2_bpp_direction {
  10. unsigned long sequence;
  11. const struct ssh2_cipher *cipher;
  12. void *cipher_ctx;
  13. const struct ssh_mac *mac;
  14. int etm_mode;
  15. void *mac_ctx;
  16. const struct ssh_compress *comp;
  17. void *comp_ctx;
  18. };
  19. struct ssh2_bpp_state {
  20. int crState;
  21. long len, pad, payload, packetlen, maclen, length, maxlen;
  22. unsigned char *buf;
  23. size_t bufsize;
  24. unsigned char *data;
  25. unsigned cipherblk;
  26. PktIn *pktin;
  27. BinarySink *sc_mac_bs;
  28. struct ssh2_bpp_direction in, out;
  29. int pending_newkeys;
  30. BinaryPacketProtocol bpp;
  31. };
  32. static void ssh2_bpp_free(BinaryPacketProtocol *bpp);
  33. static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp);
  34. static PktOut *ssh2_bpp_new_pktout(int type);
  35. static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt);
  36. const struct BinaryPacketProtocolVtable ssh2_bpp_vtable = {
  37. ssh2_bpp_free,
  38. ssh2_bpp_handle_input,
  39. ssh2_bpp_new_pktout,
  40. ssh2_bpp_format_packet,
  41. };
  42. BinaryPacketProtocol *ssh2_bpp_new(void)
  43. {
  44. struct ssh2_bpp_state *s = snew(struct ssh2_bpp_state);
  45. memset(s, 0, sizeof(*s));
  46. s->bpp.vt = &ssh2_bpp_vtable;
  47. return &s->bpp;
  48. }
  49. static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
  50. {
  51. struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
  52. sfree(s->buf);
  53. if (s->out.cipher_ctx)
  54. s->out.cipher->free_context(s->out.cipher_ctx);
  55. if (s->out.mac_ctx)
  56. s->out.mac->free_context(s->out.mac_ctx);
  57. if (s->out.comp_ctx)
  58. s->out.comp->compress_cleanup(s->out.comp_ctx);
  59. if (s->in.cipher_ctx)
  60. s->in.cipher->free_context(s->in.cipher_ctx);
  61. if (s->in.mac_ctx)
  62. s->in.mac->free_context(s->in.mac_ctx);
  63. if (s->in.comp_ctx)
  64. s->in.comp->decompress_cleanup(s->in.comp_ctx);
  65. if (s->pktin)
  66. ssh_unref_packet(s->pktin);
  67. sfree(s);
  68. }
  69. void ssh2_bpp_new_outgoing_crypto(
  70. BinaryPacketProtocol *bpp,
  71. const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
  72. const struct ssh_mac *mac, int etm_mode, const void *mac_key,
  73. const struct ssh_compress *compression)
  74. {
  75. struct ssh2_bpp_state *s;
  76. assert(bpp->vt == &ssh2_bpp_vtable);
  77. s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
  78. if (s->out.cipher_ctx)
  79. s->out.cipher->free_context(s->out.cipher_ctx);
  80. if (s->out.mac_ctx)
  81. s->out.mac->free_context(s->out.mac_ctx);
  82. if (s->out.comp_ctx)
  83. s->out.comp->compress_cleanup(s->out.comp_ctx);
  84. s->out.cipher = cipher;
  85. if (cipher) {
  86. s->out.cipher_ctx = cipher->make_context();
  87. cipher->setkey(s->out.cipher_ctx, ckey);
  88. cipher->setiv(s->out.cipher_ctx, iv);
  89. }
  90. s->out.mac = mac;
  91. s->out.etm_mode = etm_mode;
  92. if (mac) {
  93. s->out.mac_ctx = mac->make_context(s->out.cipher_ctx);
  94. mac->setkey(s->out.mac_ctx, mac_key);
  95. }
  96. s->out.comp = compression;
  97. /* out_comp is always non-NULL, because no compression is
  98. * indicated by ssh_comp_none. So compress_init always exists, but
  99. * it may return a null out_comp_ctx. */
  100. s->out.comp_ctx = compression->compress_init();
  101. }
  102. void ssh2_bpp_new_incoming_crypto(
  103. BinaryPacketProtocol *bpp,
  104. const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
  105. const struct ssh_mac *mac, int etm_mode, const void *mac_key,
  106. const struct ssh_compress *compression)
  107. {
  108. struct ssh2_bpp_state *s;
  109. assert(bpp->vt == &ssh2_bpp_vtable);
  110. s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
  111. if (s->in.cipher_ctx)
  112. s->in.cipher->free_context(s->in.cipher_ctx);
  113. if (s->in.mac_ctx)
  114. s->in.mac->free_context(s->in.mac_ctx);
  115. if (s->in.comp_ctx)
  116. s->in.comp->decompress_cleanup(s->in.comp_ctx);
  117. s->in.cipher = cipher;
  118. if (cipher) {
  119. s->in.cipher_ctx = cipher->make_context();
  120. cipher->setkey(s->in.cipher_ctx, ckey);
  121. cipher->setiv(s->in.cipher_ctx, iv);
  122. }
  123. s->in.mac = mac;
  124. s->in.etm_mode = etm_mode;
  125. if (mac) {
  126. s->in.mac_ctx = mac->make_context(s->in.cipher_ctx);
  127. mac->setkey(s->in.mac_ctx, mac_key);
  128. }
  129. s->in.comp = compression;
  130. /* in_comp is always non-NULL, because no compression is
  131. * indicated by ssh_comp_none. So compress_init always exists, but
  132. * it may return a null in_comp_ctx. */
  133. s->in.comp_ctx = compression->decompress_init();
  134. /* Clear the pending_newkeys flag, so that handle_input below will
  135. * start consuming the input data again. */
  136. s->pending_newkeys = FALSE;
  137. }
  138. static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
  139. {
  140. struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
  141. crBegin(s->crState);
  142. while (1) {
  143. s->maxlen = 0;
  144. s->length = 0;
  145. if (s->in.cipher)
  146. s->cipherblk = s->in.cipher->blksize;
  147. else
  148. s->cipherblk = 8;
  149. if (s->cipherblk < 8)
  150. s->cipherblk = 8;
  151. s->maclen = s->in.mac ? s->in.mac->len : 0;
  152. if (s->in.cipher && (s->in.cipher->flags & SSH_CIPHER_IS_CBC) &&
  153. s->in.mac && !s->in.etm_mode) {
  154. /*
  155. * When dealing with a CBC-mode cipher, we want to avoid the
  156. * possibility of an attacker's tweaking the ciphertext stream
  157. * so as to cause us to feed the same block to the block
  158. * cipher more than once and thus leak information
  159. * (VU#958563). The way we do this is not to take any
  160. * decisions on the basis of anything we've decrypted until
  161. * we've verified it with a MAC. That includes the packet
  162. * length, so we just read data and check the MAC repeatedly,
  163. * and when the MAC passes, see if the length we've got is
  164. * plausible.
  165. *
  166. * This defence is unnecessary in OpenSSH ETM mode, because
  167. * the whole point of ETM mode is that the attacker can't
  168. * tweak the ciphertext stream at all without the MAC
  169. * detecting it before we decrypt anything.
  170. */
  171. /*
  172. * Make sure we have buffer space for a maximum-size packet.
  173. */
  174. unsigned buflimit = OUR_V2_PACKETLIMIT + s->maclen;
  175. if (s->bufsize < buflimit) {
  176. s->bufsize = buflimit;
  177. s->buf = sresize(s->buf, s->bufsize, unsigned char);
  178. }
  179. /* Read an amount corresponding to the MAC. */
  180. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  181. s->bpp.in_raw, s->buf, s->maclen));
  182. s->packetlen = 0;
  183. s->in.mac->start(s->in.mac_ctx);
  184. s->sc_mac_bs = s->in.mac->sink(s->in.mac_ctx);
  185. put_uint32(s->sc_mac_bs, s->in.sequence);
  186. for (;;) { /* Once around this loop per cipher block. */
  187. /* Read another cipher-block's worth, and tack it on to
  188. * the end. */
  189. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  190. s->bpp.in_raw,
  191. s->buf + (s->packetlen + s->maclen),
  192. s->cipherblk));
  193. /* Decrypt one more block (a little further back in
  194. * the stream). */
  195. s->in.cipher->decrypt(
  196. s->in.cipher_ctx,
  197. s->buf + s->packetlen, s->cipherblk);
  198. /* Feed that block to the MAC. */
  199. put_data(s->sc_mac_bs,
  200. s->buf + s->packetlen, s->cipherblk);
  201. s->packetlen += s->cipherblk;
  202. /* See if that gives us a valid packet. */
  203. if (s->in.mac->verresult(
  204. s->in.mac_ctx, s->buf + s->packetlen) &&
  205. ((s->len = toint(GET_32BIT(s->buf))) ==
  206. s->packetlen-4))
  207. break;
  208. if (s->packetlen >= (long)OUR_V2_PACKETLIMIT) {
  209. s->bpp.error = dupprintf(
  210. "No valid incoming packet found");
  211. crStopV;
  212. }
  213. }
  214. s->maxlen = s->packetlen + s->maclen;
  215. /*
  216. * Now transfer the data into an output packet.
  217. */
  218. s->pktin = snew_plus(PktIn, s->maxlen);
  219. s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
  220. s->pktin->refcount = 1;
  221. s->pktin->type = 0;
  222. s->data = snew_plus_get_aux(s->pktin);
  223. memcpy(s->data, s->buf, s->maxlen);
  224. } else if (s->in.mac && s->in.etm_mode) {
  225. if (s->bufsize < 4) {
  226. s->bufsize = 4;
  227. s->buf = sresize(s->buf, s->bufsize, unsigned char);
  228. }
  229. /*
  230. * OpenSSH encrypt-then-MAC mode: the packet length is
  231. * unencrypted, unless the cipher supports length encryption.
  232. */
  233. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  234. s->bpp.in_raw, s->buf, 4));
  235. /* Cipher supports length decryption, so do it */
  236. if (s->in.cipher &&
  237. (s->in.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
  238. /* Keep the packet the same though, so the MAC passes */
  239. unsigned char len[4];
  240. memcpy(len, s->buf, 4);
  241. s->in.cipher->decrypt_length(
  242. s->in.cipher_ctx, len, 4, s->in.sequence);
  243. s->len = toint(GET_32BIT(len));
  244. } else {
  245. s->len = toint(GET_32BIT(s->buf));
  246. }
  247. /*
  248. * _Completely_ silly lengths should be stomped on before they
  249. * do us any more damage.
  250. */
  251. if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT ||
  252. s->len % s->cipherblk != 0) {
  253. s->bpp.error = dupprintf(
  254. "Incoming packet length field was garbled");
  255. crStopV;
  256. }
  257. /*
  258. * So now we can work out the total packet length.
  259. */
  260. s->packetlen = s->len + 4;
  261. /*
  262. * Allocate the packet to return, now we know its length.
  263. */
  264. s->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + s->maclen);
  265. s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
  266. s->pktin->refcount = 1;
  267. s->pktin->type = 0;
  268. s->data = snew_plus_get_aux(s->pktin);
  269. memcpy(s->data, s->buf, 4);
  270. /*
  271. * Read the remainder of the packet.
  272. */
  273. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  274. s->bpp.in_raw, s->data + 4,
  275. s->packetlen + s->maclen - 4));
  276. /*
  277. * Check the MAC.
  278. */
  279. if (s->in.mac && !s->in.mac->verify(
  280. s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) {
  281. s->bpp.error = dupprintf("Incorrect MAC received on packet");
  282. crStopV;
  283. }
  284. /* Decrypt everything between the length field and the MAC. */
  285. if (s->in.cipher)
  286. s->in.cipher->decrypt(
  287. s->in.cipher_ctx, s->data + 4, s->packetlen - 4);
  288. } else {
  289. if (s->bufsize < s->cipherblk) {
  290. s->bufsize = s->cipherblk;
  291. s->buf = sresize(s->buf, s->bufsize, unsigned char);
  292. }
  293. /*
  294. * Acquire and decrypt the first block of the packet. This will
  295. * contain the length and padding details.
  296. */
  297. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  298. s->bpp.in_raw, s->buf, s->cipherblk));
  299. if (s->in.cipher)
  300. s->in.cipher->decrypt(
  301. s->in.cipher_ctx, s->buf, s->cipherblk);
  302. /*
  303. * Now get the length figure.
  304. */
  305. s->len = toint(GET_32BIT(s->buf));
  306. /*
  307. * _Completely_ silly lengths should be stomped on before they
  308. * do us any more damage.
  309. */
  310. if (s->len < 0 || s->len > (long)OUR_V2_PACKETLIMIT ||
  311. (s->len + 4) % s->cipherblk != 0) {
  312. s->bpp.error = dupprintf(
  313. "Incoming packet was garbled on decryption");
  314. crStopV;
  315. }
  316. /*
  317. * So now we can work out the total packet length.
  318. */
  319. s->packetlen = s->len + 4;
  320. /*
  321. * Allocate the packet to return, now we know its length.
  322. */
  323. s->maxlen = s->packetlen + s->maclen;
  324. s->pktin = snew_plus(PktIn, s->maxlen);
  325. s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
  326. s->pktin->refcount = 1;
  327. s->pktin->type = 0;
  328. s->data = snew_plus_get_aux(s->pktin);
  329. memcpy(s->data, s->buf, s->cipherblk);
  330. /*
  331. * Read and decrypt the remainder of the packet.
  332. */
  333. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  334. s->bpp.in_raw, s->data + s->cipherblk,
  335. s->packetlen + s->maclen - s->cipherblk));
  336. /* Decrypt everything _except_ the MAC. */
  337. if (s->in.cipher)
  338. s->in.cipher->decrypt(
  339. s->in.cipher_ctx,
  340. s->data + s->cipherblk, s->packetlen - s->cipherblk);
  341. /*
  342. * Check the MAC.
  343. */
  344. if (s->in.mac && !s->in.mac->verify(
  345. s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) {
  346. s->bpp.error = dupprintf("Incorrect MAC received on packet");
  347. crStopV;
  348. }
  349. }
  350. /* Get and sanity-check the amount of random padding. */
  351. s->pad = s->data[4];
  352. if (s->pad < 4 || s->len - s->pad < 1) {
  353. s->bpp.error = dupprintf(
  354. "Invalid padding length on received packet");
  355. crStopV;
  356. }
  357. /*
  358. * This enables us to deduce the payload length.
  359. */
  360. s->payload = s->len - s->pad - 1;
  361. s->length = s->payload + 5;
  362. s->pktin->encrypted_len = s->packetlen;
  363. s->pktin->sequence = s->in.sequence++;
  364. s->length = s->packetlen - s->pad;
  365. assert(s->length >= 0);
  366. /*
  367. * Decompress packet payload.
  368. */
  369. {
  370. unsigned char *newpayload;
  371. int newlen;
  372. if (s->in.comp && s->in.comp->decompress(
  373. s->in.comp_ctx, s->data + 5, s->length - 5,
  374. &newpayload, &newlen)) {
  375. if (s->maxlen < newlen + 5) {
  376. PktIn *old_pktin = s->pktin;
  377. s->maxlen = newlen + 5;
  378. s->pktin = snew_plus(PktIn, s->maxlen);
  379. *s->pktin = *old_pktin; /* structure copy */
  380. s->data = snew_plus_get_aux(s->pktin);
  381. smemclr(old_pktin, s->packetlen + s->maclen);
  382. sfree(old_pktin);
  383. }
  384. s->length = 5 + newlen;
  385. memcpy(s->data + 5, newpayload, newlen);
  386. sfree(newpayload);
  387. }
  388. }
  389. /*
  390. * Now we can identify the semantic content of the packet,
  391. * and also the initial type byte.
  392. */
  393. if (s->length <= 5) { /* == 5 we hope, but robustness */
  394. /*
  395. * RFC 4253 doesn't explicitly say that completely empty
  396. * packets with no type byte are forbidden. We handle them
  397. * here by giving them a type code larger than 0xFF, which
  398. * will be picked up at the next layer and trigger
  399. * SSH_MSG_UNIMPLEMENTED.
  400. */
  401. s->pktin->type = SSH_MSG_NO_TYPE_CODE;
  402. s->length = 0;
  403. BinarySource_INIT(s->pktin, s->data + 5, 0);
  404. } else {
  405. s->pktin->type = s->data[5];
  406. s->length -= 6;
  407. BinarySource_INIT(s->pktin, s->data + 6, s->length);
  408. }
  409. if (s->bpp.logctx) {
  410. logblank_t blanks[MAX_BLANKS];
  411. int nblanks = ssh2_censor_packet(
  412. s->bpp.pls, s->pktin->type, FALSE,
  413. make_ptrlen(s->data, s->length), blanks);
  414. log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
  415. ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
  416. s->pktin->type),
  417. get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
  418. &s->pktin->sequence, 0, NULL);
  419. }
  420. pq_push(s->bpp.in_pq, s->pktin);
  421. {
  422. int type = s->pktin->type;
  423. s->pktin = NULL;
  424. if (type == SSH2_MSG_DISCONNECT)
  425. s->bpp.seen_disconnect = TRUE;
  426. if (type == SSH2_MSG_NEWKEYS) {
  427. /*
  428. * Mild layer violation: in this situation we must
  429. * suspend processing of the input byte stream until
  430. * the transport layer has initialised the new keys by
  431. * calling ssh2_bpp_new_incoming_crypto above.
  432. */
  433. s->pending_newkeys = TRUE;
  434. crWaitUntilV(!s->pending_newkeys);
  435. }
  436. }
  437. }
  438. crFinishV;
  439. }
  440. static PktOut *ssh2_bpp_new_pktout(int pkt_type)
  441. {
  442. PktOut *pkt = ssh_new_packet();
  443. pkt->length = 5; /* space for packet length + padding length */
  444. pkt->minlen = 0;
  445. pkt->type = pkt_type;
  446. put_byte(pkt, pkt_type);
  447. pkt->prefix = pkt->length;
  448. return pkt;
  449. }
  450. static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
  451. {
  452. int origlen, cipherblk, maclen, padding, unencrypted_prefix, i;
  453. if (s->bpp.logctx) {
  454. ptrlen pktdata = make_ptrlen(pkt->data + pkt->prefix,
  455. pkt->length - pkt->prefix);
  456. logblank_t blanks[MAX_BLANKS];
  457. int nblanks = ssh2_censor_packet(
  458. s->bpp.pls, pkt->type, TRUE, pktdata, blanks);
  459. log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
  460. ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
  461. pkt->type),
  462. pktdata.ptr, pktdata.len, nblanks, blanks, &s->out.sequence,
  463. pkt->downstream_id, pkt->additional_log_text);
  464. }
  465. cipherblk = s->out.cipher ? s->out.cipher->blksize : 8;
  466. cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */
  467. if (s->out.comp && s->out.comp_ctx) {
  468. unsigned char *newpayload;
  469. int minlen, newlen;
  470. /*
  471. * Compress packet payload.
  472. */
  473. minlen = pkt->minlen;
  474. if (minlen) {
  475. /*
  476. * Work out how much compressed data we need (at least) to
  477. * make the overall packet length come to pkt->minlen.
  478. */
  479. if (s->out.mac)
  480. minlen -= s->out.mac->len;
  481. minlen -= 8; /* length field + min padding */
  482. }
  483. s->out.comp->compress(s->out.comp_ctx, pkt->data + 5, pkt->length - 5,
  484. &newpayload, &newlen, minlen);
  485. pkt->length = 5;
  486. put_data(pkt, newpayload, newlen);
  487. sfree(newpayload);
  488. }
  489. /*
  490. * Add padding. At least four bytes, and must also bring total
  491. * length (minus MAC) up to a multiple of the block size.
  492. * If pkt->forcepad is set, make sure the packet is at least that size
  493. * after padding.
  494. */
  495. padding = 4;
  496. unencrypted_prefix = (s->out.mac && s->out.etm_mode) ? 4 : 0;
  497. padding +=
  498. (cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk)
  499. % cipherblk;
  500. assert(padding <= 255);
  501. maclen = s->out.mac ? s->out.mac->len : 0;
  502. origlen = pkt->length;
  503. for (i = 0; i < padding; i++)
  504. put_byte(pkt, random_byte());
  505. pkt->data[4] = padding;
  506. PUT_32BIT(pkt->data, origlen + padding - 4);
  507. /* Encrypt length if the scheme requires it */
  508. if (s->out.cipher &&
  509. (s->out.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
  510. s->out.cipher->encrypt_length(s->out.cipher_ctx, pkt->data, 4,
  511. s->out.sequence);
  512. }
  513. put_padding(pkt, maclen, 0);
  514. if (s->out.mac && s->out.etm_mode) {
  515. /*
  516. * OpenSSH-defined encrypt-then-MAC protocol.
  517. */
  518. if (s->out.cipher)
  519. s->out.cipher->encrypt(s->out.cipher_ctx,
  520. pkt->data + 4, origlen + padding - 4);
  521. s->out.mac->generate(s->out.mac_ctx, pkt->data, origlen + padding,
  522. s->out.sequence);
  523. } else {
  524. /*
  525. * SSH-2 standard protocol.
  526. */
  527. if (s->out.mac)
  528. s->out.mac->generate(
  529. s->out.mac_ctx, pkt->data, origlen + padding,
  530. s->out.sequence);
  531. if (s->out.cipher)
  532. s->out.cipher->encrypt(s->out.cipher_ctx,
  533. pkt->data, origlen + padding);
  534. }
  535. s->out.sequence++; /* whether or not we MACed */
  536. pkt->encrypted_len = origlen + padding;
  537. }
  538. static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
  539. {
  540. struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
  541. if (pkt->minlen > 0 && !(s->out.comp && s->out.comp_ctx)) {
  542. /*
  543. * If we've been told to pad the packet out to a given minimum
  544. * length, but we're not compressing (and hence can't get the
  545. * compression to do the padding by pointlessly opening and
  546. * closing zlib blocks), then our other strategy is to precede
  547. * this message with an SSH_MSG_IGNORE that makes it up to the
  548. * right length.
  549. *
  550. * A third option in principle, and the most obviously
  551. * sensible, would be to set the explicit padding field in the
  552. * packet to more than its minimum value. Sadly, that turns
  553. * out to break some servers (our institutional memory thinks
  554. * Cisco in particular) and so we abandoned that idea shortly
  555. * after trying it.
  556. */
  557. /*
  558. * Calculate the length we expect the real packet to have.
  559. */
  560. int block, length;
  561. PktOut *ignore_pkt;
  562. block = s->out.cipher ? s->out.cipher->blksize : 0;
  563. if (block < 8)
  564. block = 8;
  565. length = pkt->length;
  566. length += 4; /* minimum 4 byte padding */
  567. length += block-1;
  568. length -= (length % block);
  569. if (s->out.mac)
  570. length += s->out.mac->len;
  571. if (length < pkt->minlen) {
  572. /*
  573. * We need an ignore message. Calculate its length.
  574. */
  575. length = pkt->minlen - length;
  576. /*
  577. * And work backwards from that to the length of the
  578. * contained string.
  579. */
  580. if (s->out.mac)
  581. length -= s->out.mac->len;
  582. length -= 8; /* length field + min padding */
  583. length -= 5; /* type code + string length prefix */
  584. if (length < 0)
  585. length = 0;
  586. ignore_pkt = ssh2_bpp_new_pktout(SSH2_MSG_IGNORE);
  587. put_uint32(ignore_pkt, length);
  588. while (length-- > 0)
  589. put_byte(ignore_pkt, random_byte());
  590. ssh2_bpp_format_packet_inner(s, ignore_pkt);
  591. bufchain_add(s->bpp.out_raw, ignore_pkt->data, ignore_pkt->length);
  592. ssh_free_pktout(ignore_pkt);
  593. }
  594. }
  595. ssh2_bpp_format_packet_inner(s, pkt);
  596. bufchain_add(s->bpp.out_raw, pkt->data, pkt->length);
  597. ssh_free_pktout(pkt);
  598. }
  599. #ifdef MPEXT
  600. const struct ssh2_cipher * ssh2_bpp_get_cscipher(BinaryPacketProtocol *bpp)
  601. {
  602. return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->out.cipher;
  603. }
  604. const struct ssh2_cipher * ssh2_bpp_get_sccipher(BinaryPacketProtocol *bpp)
  605. {
  606. return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->in.cipher;
  607. }
  608. const struct ssh_compress * ssh2_bpp_get_cscomp(BinaryPacketProtocol *bpp)
  609. {
  610. return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->out.comp;
  611. }
  612. const struct ssh_compress * ssh2_bpp_get_sccomp(BinaryPacketProtocol *bpp)
  613. {
  614. return FROMFIELD(bpp, struct ssh2_bpp_state, bpp)->in.comp;
  615. }
  616. #endif