1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-06 14:02:47 -05:00

Turn SSH-2 MACs into a classoid.

This piece of tidying-up has come out particularly well in terms of
saving tedious repetition and boilerplate. I've managed to remove
three pointless methods from every MAC implementation by means of
writing them once centrally in terms of the implementation-specific
methods; another method (hmacmd5_sink) vanished because I was able to
make the interface type 'ssh2_mac' be directly usable as a BinarySink
by way of a new delegation system; and because all the method
implementations can now find their own vtable, I was even able to
merge a lot of keying and output functions that had previously
differed only in length parameters by having them look up the lengths
in whatever vtable they were passed.
This commit is contained in:
Simon Tatham
2018-09-13 16:15:17 +01:00
parent 229af2b5bf
commit 853bd8b284
12 changed files with 294 additions and 397 deletions

View File

@ -12,9 +12,8 @@
struct ssh2_bpp_direction {
unsigned long sequence;
ssh2_cipher *cipher;
const struct ssh_mac *mac;
ssh2_mac *mac;
int etm_mode;
void *mac_ctx;
const struct ssh_compress *comp;
void *comp_ctx;
};
@ -27,7 +26,6 @@ struct ssh2_bpp_state {
unsigned char *data;
unsigned cipherblk;
PktIn *pktin;
BinarySink *sc_mac_bs;
struct ssh2_bpp_direction in, out;
int pending_newkeys;
@ -61,14 +59,14 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
sfree(s->buf);
if (s->out.cipher)
ssh2_cipher_free(s->out.cipher);
if (s->out.mac_ctx)
s->out.mac->free_context(s->out.mac_ctx);
if (s->out.mac)
ssh2_mac_free(s->out.mac);
if (s->out.comp_ctx)
s->out.comp->compress_cleanup(s->out.comp_ctx);
if (s->in.cipher)
ssh2_cipher_free(s->in.cipher);
if (s->in.mac_ctx)
s->in.mac->free_context(s->in.mac_ctx);
if (s->in.mac)
ssh2_mac_free(s->in.mac);
if (s->in.comp_ctx)
s->in.comp->decompress_cleanup(s->in.comp_ctx);
if (s->pktin)
@ -79,7 +77,7 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
void ssh2_bpp_new_outgoing_crypto(
BinaryPacketProtocol *bpp,
const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
const struct ssh2_macalg *mac, int etm_mode, const void *mac_key,
const struct ssh_compress *compression)
{
struct ssh2_bpp_state *s;
@ -88,8 +86,8 @@ void ssh2_bpp_new_outgoing_crypto(
if (s->out.cipher)
ssh2_cipher_free(s->out.cipher);
if (s->out.mac_ctx)
s->out.mac->free_context(s->out.mac_ctx);
if (s->out.mac)
ssh2_mac_free(s->out.mac);
if (s->out.comp_ctx)
s->out.comp->compress_cleanup(s->out.comp_ctx);
@ -100,11 +98,12 @@ void ssh2_bpp_new_outgoing_crypto(
} else {
s->out.cipher = NULL;
}
s->out.mac = mac;
s->out.etm_mode = etm_mode;
if (mac) {
s->out.mac_ctx = mac->make_context(s->out.cipher);
mac->setkey(s->out.mac_ctx, mac_key);
s->out.mac = ssh2_mac_new(mac, s->out.cipher);
mac->setkey(s->out.mac, mac_key);
} else {
s->out.mac = NULL;
}
s->out.comp = compression;
@ -117,7 +116,7 @@ void ssh2_bpp_new_outgoing_crypto(
void ssh2_bpp_new_incoming_crypto(
BinaryPacketProtocol *bpp,
const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
const struct ssh2_macalg *mac, int etm_mode, const void *mac_key,
const struct ssh_compress *compression)
{
struct ssh2_bpp_state *s;
@ -126,8 +125,8 @@ void ssh2_bpp_new_incoming_crypto(
if (s->in.cipher)
ssh2_cipher_free(s->in.cipher);
if (s->in.mac_ctx)
s->in.mac->free_context(s->in.mac_ctx);
if (s->in.mac)
ssh2_mac_free(s->in.mac);
if (s->in.comp_ctx)
s->in.comp->decompress_cleanup(s->in.comp_ctx);
@ -138,11 +137,12 @@ void ssh2_bpp_new_incoming_crypto(
} else {
s->in.cipher = NULL;
}
s->in.mac = mac;
s->in.etm_mode = etm_mode;
if (mac) {
s->in.mac_ctx = mac->make_context(s->in.cipher);
mac->setkey(s->in.mac_ctx, mac_key);
s->in.mac = ssh2_mac_new(mac, s->in.cipher);
mac->setkey(s->in.mac, mac_key);
} else {
s->in.mac = NULL;
}
s->in.comp = compression;
@ -171,7 +171,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
s->cipherblk = 8;
if (s->cipherblk < 8)
s->cipherblk = 8;
s->maclen = s->in.mac ? s->in.mac->len : 0;
s->maclen = s->in.mac ? ssh2_mac_alg(s->in.mac)->len : 0;
if (s->in.cipher &&
(ssh2_cipher_alg(s->in.cipher)->flags & SSH_CIPHER_IS_CBC) &&
@ -208,9 +208,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
s->bpp.in_raw, s->buf, s->maclen));
s->packetlen = 0;
s->in.mac->start(s->in.mac_ctx);
s->sc_mac_bs = s->in.mac->sink(s->in.mac_ctx);
put_uint32(s->sc_mac_bs, s->in.sequence);
ssh2_mac_start(s->in.mac);
put_uint32(s->in.mac, s->in.sequence);
for (;;) { /* Once around this loop per cipher block. */
/* Read another cipher-block's worth, and tack it on to
@ -225,13 +224,12 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
s->buf + s->packetlen, s->cipherblk);
/* Feed that block to the MAC. */
put_data(s->sc_mac_bs,
put_data(s->in.mac,
s->buf + s->packetlen, s->cipherblk);
s->packetlen += s->cipherblk;
/* See if that gives us a valid packet. */
if (s->in.mac->verresult(
s->in.mac_ctx, s->buf + s->packetlen) &&
if (ssh2_mac_verresult(s->in.mac, s->buf + s->packetlen) &&
((s->len = toint(GET_32BIT(s->buf))) ==
s->packetlen-4))
break;
@ -314,8 +312,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
/*
* Check the MAC.
*/
if (s->in.mac && !s->in.mac->verify(
s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) {
if (s->in.mac && !ssh2_mac_verify(
s->in.mac, s->data, s->len + 4, s->in.sequence)) {
s->bpp.error = dupprintf("Incorrect MAC received on packet");
crStopV;
}
@ -389,8 +387,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
/*
* Check the MAC.
*/
if (s->in.mac && !s->in.mac->verify(
s->in.mac_ctx, s->data, s->len + 4, s->in.sequence)) {
if (s->in.mac && !ssh2_mac_verify(
s->in.mac, s->data, s->len + 4, s->in.sequence)) {
s->bpp.error = dupprintf("Incorrect MAC received on packet");
crStopV;
}
@ -542,7 +540,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
* make the overall packet length come to pkt->minlen.
*/
if (s->out.mac)
minlen -= s->out.mac->len;
minlen -= ssh2_mac_alg(s->out.mac)->len;
minlen -= 8; /* length field + min padding */
}
@ -565,7 +563,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
(cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk)
% cipherblk;
assert(padding <= 255);
maclen = s->out.mac ? s->out.mac->len : 0;
maclen = s->out.mac ? ssh2_mac_alg(s->out.mac)->len : 0;
origlen = pkt->length;
for (i = 0; i < padding; i++)
put_byte(pkt, random_byte());
@ -588,16 +586,15 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
if (s->out.cipher)
ssh2_cipher_encrypt(s->out.cipher,
pkt->data + 4, origlen + padding - 4);
s->out.mac->generate(s->out.mac_ctx, pkt->data, origlen + padding,
s->out.sequence);
ssh2_mac_generate(s->out.mac, pkt->data, origlen + padding,
s->out.sequence);
} else {
/*
* SSH-2 standard protocol.
*/
if (s->out.mac)
s->out.mac->generate(
s->out.mac_ctx, pkt->data, origlen + padding,
s->out.sequence);
ssh2_mac_generate(s->out.mac, pkt->data, origlen + padding,
s->out.sequence);
if (s->out.cipher)
ssh2_cipher_encrypt(s->out.cipher, pkt->data, origlen + padding);
}
@ -642,7 +639,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
length += block-1;
length -= (length % block);
if (s->out.mac)
length += s->out.mac->len;
length += ssh2_mac_alg(s->out.mac)->len;
if (length < pkt->minlen) {
/*
@ -655,7 +652,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
* contained string.
*/
if (s->out.mac)
length -= s->out.mac->len;
length -= ssh2_mac_alg(s->out.mac)->len;
length -= 8; /* length field + min padding */
length -= 5; /* type code + string length prefix */