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:
75
ssh2bpp.c
75
ssh2bpp.c
@ -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 */
|
||||
|
||||
|
Reference in New Issue
Block a user