diff --git a/Recipe b/Recipe index 5af98117..b735ac47 100644 --- a/Recipe +++ b/Recipe @@ -255,6 +255,7 @@ SSH = ssh ssh1bpp ssh2bpp ssh2bpp-bare ssh1censor ssh2censor + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshccp sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi sshshare sshecc aqsync marshal nullplug agentf + + sshmac WINSSH = SSH winnoise wincapi winpgntc wingss winshare winnps winnpc + winhsock errsock UXSSH = SSH uxnoise uxagentc uxgss uxshare diff --git a/cproxy.c b/cproxy.c index 142c2a17..5d5439fa 100644 --- a/cproxy.c +++ b/cproxy.c @@ -19,10 +19,10 @@ static void hmacmd5_chap(const unsigned char *challenge, int challen, const char *passwd, unsigned char *response) { - void *hmacmd5_ctx; + struct hmacmd5_context *hmacmd5_ctx; int pwlen; - hmacmd5_ctx = hmacmd5_make_context(NULL); + hmacmd5_ctx = hmacmd5_make_context(); pwlen = strlen(passwd); if (pwlen>64) { diff --git a/marshal.h b/marshal.h index 2aa0301a..631e2465 100644 --- a/marshal.h +++ b/marshal.h @@ -25,6 +25,17 @@ struct BinarySink { ((obj)->binarysink_->write = (writefn), \ (obj)->binarysink_->binarysink_ = (obj)->binarysink_) +/* + * To define a larger structure type as a valid BinarySink in such a + * way that it will delegate the write method to some other object, + * put 'BinarySink_DELEGATE_IMPLEMENTATION' in its declaration, and + * when an instance is set up, use 'BinarySink_DELEGATE_INIT' to point + * at the object it wants to delegate to. + */ +#define BinarySink_DELEGATE_IMPLEMENTATION BinarySink *binarysink_ +#define BinarySink_DELEGATE_INIT(obj, othersink) \ + ((obj)->binarysink_ = BinarySink_UPCAST(othersink)) + /* * The implementing type's write function will want to downcast its * 'BinarySink *' parameter back to the more specific type. Also, diff --git a/ssh.c b/ssh.c index 1ece7488..814d28b7 100644 --- a/ssh.c +++ b/ssh.c @@ -328,10 +328,10 @@ const static struct ssh_signkey_with_user_pref_id hostkey_algs[] = { { &ssh_rsa, HK_RSA }, }; -const static struct ssh_mac *const macs[] = { +const static struct ssh2_macalg *const macs[] = { &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5 }; -const static struct ssh_mac *const buggymacs[] = { +const static struct ssh2_macalg *const buggymacs[] = { &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5 }; @@ -4854,7 +4854,7 @@ struct kexinit_algorithm { int warn; } cipher; struct { - const struct ssh_mac *mac; + const struct ssh2_macalg *mac; int etm; } mac; const struct ssh_compress *comp; @@ -5023,11 +5023,11 @@ static void do_ssh2_transport(void *vctx) void *our_kexinit; int our_kexinitlen; int kex_init_value, kex_reply_value; - const struct ssh_mac *const *maclist; + const struct ssh2_macalg *const *maclist; int nmacs; struct { const struct ssh2_cipheralg *cipher; - const struct ssh_mac *mac; + const struct ssh2_macalg *mac; int etm_mode; const struct ssh_compress *comp; } in, out; diff --git a/ssh.h b/ssh.h index a856aa9e..6b768a8a 100644 --- a/ssh.h +++ b/ssh.h @@ -374,11 +374,12 @@ void MD5Init(struct MD5Context *context); void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Simple(void const *p, unsigned len, unsigned char output[16]); -void *hmacmd5_make_context(ssh2_cipher *); -void hmacmd5_free_context(void *handle); -void hmacmd5_key(void *handle, void const *key, int len); -void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len, - unsigned char *hmac); +struct hmacmd5_context; +struct hmacmd5_context *hmacmd5_make_context(void); +void hmacmd5_free_context(struct hmacmd5_context *ctx); +void hmacmd5_key(struct hmacmd5_context *ctx, void const *key, int len); +void hmacmd5_do_hmac(struct hmacmd5_context *ctx, + unsigned char const *blk, int len, unsigned char *hmac); int supports_sha_ni(void); @@ -476,7 +477,7 @@ struct ssh2_cipheralg { #define SSH_CIPHER_SEPARATE_LENGTH 2 const char *text_name; /* If set, this takes priority over other MAC. */ - const struct ssh_mac *required_mac; + const struct ssh2_macalg *required_mac; }; #define ssh2_cipher_new(alg) ((alg)->new(alg)) @@ -496,24 +497,36 @@ struct ssh2_ciphers { const struct ssh2_cipheralg *const *list; }; -struct ssh_mac { +struct ssh2_macalg; +typedef struct ssh2_mac { + const struct ssh2_macalg *vt; + BinarySink_DELEGATE_IMPLEMENTATION; +} ssh2_mac; + +struct ssh2_macalg { /* Passes in the cipher context */ - void *(*make_context)(ssh2_cipher *); - void (*free_context)(void *); - void (*setkey) (void *, const void *key); - /* whole-packet operations */ - void (*generate) (void *, void *blk, int len, unsigned long seq); - int (*verify) (void *, const void *blk, int len, unsigned long seq); - /* partial-packet operations */ - void (*start) (void *); - BinarySink *(*sink) (void *); - void (*genresult) (void *, unsigned char *); - int (*verresult) (void *, unsigned char const *); + ssh2_mac *(*new)(const struct ssh2_macalg *alg, ssh2_cipher *cipher); + void (*free)(ssh2_mac *); + void (*setkey)(ssh2_mac *, const void *key); + void (*start)(ssh2_mac *); + void (*genresult)(ssh2_mac *, unsigned char *); const char *name, *etm_name; int len, keylen; const char *text_name; }; +#define ssh2_mac_new(alg, cipher) ((alg)->new(alg, cipher)) +#define ssh2_mac_free(ctx) ((ctx)->vt->free(ctx)) +#define ssh2_mac_setkey(ctx, key) ((ctx)->vt->free(ctx, key)) +#define ssh2_mac_start(ctx) ((ctx)->vt->start(ctx)) +#define ssh2_mac_genresult(ctx, out) ((ctx)->vt->genresult(ctx, out)) +#define ssh2_mac_alg(ctx) ((ctx)->vt) + +/* Centralised 'methods' for ssh2_mac, defined in sshmac.c */ +int ssh2_mac_verresult(ssh2_mac *, const void *); +void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq); +int ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq); + struct ssh_hash { void *(*init)(void); /* also allocates context */ void *(*copy)(const void *); @@ -628,12 +641,12 @@ extern const ssh_keyalg ssh_ecdsa_ed25519; extern const ssh_keyalg ssh_ecdsa_nistp256; extern const ssh_keyalg ssh_ecdsa_nistp384; extern const ssh_keyalg ssh_ecdsa_nistp521; -extern const struct ssh_mac ssh_hmac_md5; -extern const struct ssh_mac ssh_hmac_sha1; -extern const struct ssh_mac ssh_hmac_sha1_buggy; -extern const struct ssh_mac ssh_hmac_sha1_96; -extern const struct ssh_mac ssh_hmac_sha1_96_buggy; -extern const struct ssh_mac ssh_hmac_sha256; +extern const struct ssh2_macalg ssh_hmac_md5; +extern const struct ssh2_macalg ssh_hmac_sha1; +extern const struct ssh2_macalg ssh_hmac_sha1_buggy; +extern const struct ssh2_macalg ssh_hmac_sha1_96; +extern const struct ssh2_macalg ssh_hmac_sha1_96_buggy; +extern const struct ssh2_macalg ssh_hmac_sha256; typedef struct AESContext AESContext; AESContext *aes_make_context(void); diff --git a/ssh2bpp.c b/ssh2bpp.c index 510e21a5..ff957b05 100644 --- a/ssh2bpp.c +++ b/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 */ diff --git a/sshbpp.h b/sshbpp.h index 41683410..f7e2fe2c 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -40,12 +40,12 @@ BinaryPacketProtocol *ssh2_bpp_new(void); 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); 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); BinaryPacketProtocol *ssh2_bare_bpp_new(void); diff --git a/sshccp.c b/sshccp.c index 9919ced2..dfcb02c8 100644 --- a/sshccp.c +++ b/sshccp.c @@ -866,27 +866,32 @@ struct ccp_context { struct poly1305 mac; BinarySink_IMPLEMENTATION; - ssh2_cipher vt; + ssh2_cipher cvt; + ssh2_mac mac_if; }; -static void *poly_make_context(ssh2_cipher *cipher) +static ssh2_mac *poly_ssh2_new( + const struct ssh2_macalg *alg, ssh2_cipher *cipher) { - return FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); + ctx->mac_if.vt = alg; + BinarySink_DELEGATE_INIT(&ctx->mac_if, ctx); + return &ctx->mac_if; } -static void poly_free_context(void *ctx) +static void poly_ssh2_free(ssh2_mac *mac) { /* Not allocated, just forwarded, no need to free */ } -static void poly_setkey(void *ctx, const void *key) +static void poly_setkey(ssh2_mac *mac, const void *key) { /* Uses the same context as ChaCha20, so ignore */ } -static void poly_start(void *handle) +static void poly_start(ssh2_mac *mac) { - struct ccp_context *ctx = (struct ccp_context *)handle; + struct ccp_context *ctx = FROMFIELD(mac, struct ccp_context, mac_if); ctx->mac_initialised = 0; memset(ctx->mac_iv, 0, 8); @@ -926,63 +931,15 @@ static void poly_BinarySink_write(BinarySink *bs, const void *blkv, size_t len) } } -static BinarySink *poly_sink(void *handle) +static void poly_genresult(ssh2_mac *mac, unsigned char *blk) { - struct ccp_context *ctx = (struct ccp_context *)handle; - return BinarySink_UPCAST(ctx); -} - -static void poly_genresult(void *handle, unsigned char *blk) -{ - struct ccp_context *ctx = (struct ccp_context *)handle; + struct ccp_context *ctx = FROMFIELD(mac, struct ccp_context, mac_if); poly1305_finalise(&ctx->mac, blk); } -static int poly_verresult(void *handle, unsigned char const *blk) -{ - struct ccp_context *ctx = (struct ccp_context *)handle; - int res; - unsigned char mac[16]; - poly1305_finalise(&ctx->mac, mac); - res = smemeq(blk, mac, 16); - return res; -} - -/* The generic poly operation used before generate and verify */ -static void poly_op(void *handle, const unsigned char *blk, int len, - unsigned long seq) -{ - struct ccp_context *ctx = (struct ccp_context *)handle; - poly_start(ctx); - /* the data receiver expects the first 4 bytes to be the IV */ - put_uint32(ctx, seq); - put_data(ctx, blk, len); -} - -static void poly_generate(void *handle, void *vblk, int len, unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - poly_op(handle, blk, len, seq); - poly_genresult(handle, blk+len); -} - -static int poly_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - poly_op(handle, blk, len, seq); - return poly_verresult(handle, blk+len); -} - -static const struct ssh_mac ssh2_poly1305 = { - poly_make_context, poly_free_context, - poly_setkey, - - /* whole-packet operations */ - poly_generate, poly_verify, - - /* partial-packet operations */ - poly_start, poly_sink, poly_genresult, poly_verresult, +static const struct ssh2_macalg ssh2_poly1305 = { + poly_ssh2_new, poly_ssh2_free, poly_setkey, + poly_start, poly_genresult, "", "", /* Not selectable individually, just part of ChaCha20-Poly1305 */ 16, 0, "Poly1305" @@ -993,13 +950,13 @@ static ssh2_cipher *ccp_new(const struct ssh2_cipheralg *alg) struct ccp_context *ctx = snew(struct ccp_context); BinarySink_INIT(ctx, poly_BinarySink_write); poly1305_init(&ctx->mac); - ctx->vt = alg; - return &ctx->vt; + ctx->cvt = alg; + return &ctx->cvt; } static void ccp_free(ssh2_cipher *cipher) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); smemclr(&ctx->a_cipher, sizeof(ctx->a_cipher)); smemclr(&ctx->b_cipher, sizeof(ctx->b_cipher)); smemclr(&ctx->mac, sizeof(ctx->mac)); @@ -1008,14 +965,14 @@ static void ccp_free(ssh2_cipher *cipher) static void ccp_iv(ssh2_cipher *cipher, const void *iv) { - /* struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); */ + /* struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); */ /* IV is set based on the sequence number */ } static void ccp_key(ssh2_cipher *cipher, const void *vkey) { const unsigned char *key = (const unsigned char *)vkey; - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); /* Initialise the a_cipher (for decrypting lengths) with the first 256 bits */ chacha20_key(&ctx->a_cipher, key + 32); /* Initialise the b_cipher (for content and MAC) with the second 256 bits */ @@ -1024,13 +981,13 @@ static void ccp_key(ssh2_cipher *cipher, const void *vkey) static void ccp_encrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); chacha20_encrypt(&ctx->b_cipher, blk, len); } static void ccp_decrypt(ssh2_cipher *cipher, void *blk, int len) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); chacha20_decrypt(&ctx->b_cipher, blk, len); } @@ -1054,7 +1011,7 @@ static void ccp_length_op(struct ccp_context *ctx, void *blk, int len, static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); ccp_length_op(ctx, blk, len, seq); chacha20_encrypt(&ctx->a_cipher, blk, len); } @@ -1062,7 +1019,7 @@ static void ccp_encrypt_length(ssh2_cipher *cipher, void *blk, int len, static void ccp_decrypt_length(ssh2_cipher *cipher, void *blk, int len, unsigned long seq) { - struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, vt); + struct ccp_context *ctx = FROMFIELD(cipher, struct ccp_context, cvt); ccp_length_op(ctx, blk, len, seq); chacha20_decrypt(&ctx->a_cipher, blk, len); } diff --git a/sshmac.c b/sshmac.c new file mode 100644 index 00000000..e3b74b38 --- /dev/null +++ b/sshmac.c @@ -0,0 +1,42 @@ +/* + * Centralised parts of the SSH-2 MAC API, which don't need to vary + * with the MAC implementation. + */ + +#include + +#include "ssh.h" + +int ssh2_mac_verresult(ssh2_mac *mac, const void *candidate) +{ + unsigned char correct[64]; /* at least as big as all known MACs */ + int toret; + + assert(mac->vt->len <= sizeof(correct)); + ssh2_mac_genresult(mac, correct); + toret = smemeq(correct, candidate, mac->vt->len); + + smemclr(correct, sizeof(correct)); + + return toret; +} + +static void ssh2_mac_prepare(ssh2_mac *mac, const void *blk, int len, + unsigned long seq) +{ + ssh2_mac_start(mac); + put_uint32(mac, seq); + put_data(mac, blk, len); +} + +void ssh2_mac_generate(ssh2_mac *mac, void *blk, int len, unsigned long seq) +{ + ssh2_mac_prepare(mac, blk, len, seq); + return ssh2_mac_genresult(mac, (unsigned char *)blk + len); +} + +int ssh2_mac_verify(ssh2_mac *mac, const void *blk, int len, unsigned long seq) +{ + ssh2_mac_prepare(mac, blk, len, seq); + return ssh2_mac_verresult(mac, (const unsigned char *)blk + len); +} diff --git a/sshmd5.c b/sshmd5.c index be3b96cf..87a224d9 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -228,20 +228,40 @@ void MD5Simple(void const *p, unsigned len, unsigned char output[16]) * useful elsewhere (SOCKS5 CHAP authentication uses HMAC-MD5). */ -void *hmacmd5_make_context(ssh2_cipher *cipher) +struct hmacmd5_context { + struct MD5Context md5[3]; + ssh2_mac mac; +}; + +struct hmacmd5_context *hmacmd5_make_context(void) { - return snewn(3, struct MD5Context); + struct hmacmd5_context *ctx = snew(struct hmacmd5_context); + BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->md5[2]); + return ctx; } -void hmacmd5_free_context(void *handle) +static ssh2_mac *hmacmd5_ssh2_new(const struct ssh2_macalg *alg, + ssh2_cipher *cipher) { - smemclr(handle, 3*sizeof(struct MD5Context)); - sfree(handle); + struct hmacmd5_context *ctx = hmacmd5_make_context(); + ctx->mac.vt = alg; + return &ctx->mac; } -void hmacmd5_key(void *handle, void const *keyv, int len) +void hmacmd5_free_context(struct hmacmd5_context *ctx) +{ + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); +} + +static void hmacmd5_ssh2_free(ssh2_mac *mac) +{ + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + hmacmd5_free_context(ctx); +} + +void hmacmd5_key(struct hmacmd5_context *ctx, void const *keyv, int len) { - struct MD5Context *keys = (struct MD5Context *)handle; unsigned char foo[64]; unsigned char const *key = (unsigned char const *)keyv; int i; @@ -249,106 +269,59 @@ void hmacmd5_key(void *handle, void const *keyv, int len) memset(foo, 0x36, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - MD5Init(&keys[0]); - put_data(&keys[0], foo, 64); + MD5Init(&ctx->md5[0]); + put_data(&ctx->md5[0], foo, 64); memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - MD5Init(&keys[1]); - put_data(&keys[1], foo, 64); + MD5Init(&ctx->md5[1]); + put_data(&ctx->md5[1], foo, 64); smemclr(foo, 64); /* burn the evidence */ } -static void hmacmd5_key_16(void *handle, const void *key) +static void hmacmd5_ssh2_setkey(ssh2_mac *mac, const void *key) { - hmacmd5_key(handle, key, 16); + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); + hmacmd5_key(ctx, key, ctx->mac.vt->keylen); } -static void hmacmd5_start(void *handle) +static void hmacmd5_start(ssh2_mac *mac) { - struct MD5Context *keys = (struct MD5Context *)handle; + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); - keys[2] = keys[0]; /* structure copy */ - BinarySink_COPIED(&keys[2]); + ctx->md5[2] = ctx->md5[0]; /* structure copy */ + BinarySink_COPIED(&ctx->md5[2]); } -static BinarySink *hmacmd5_sink(void *handle) +static void hmacmd5_genresult(ssh2_mac *mac, unsigned char *hmac) { - struct MD5Context *keys = (struct MD5Context *)handle; - return BinarySink_UPCAST(&keys[2]); -} - -static void hmacmd5_genresult(void *handle, unsigned char *hmac) -{ - struct MD5Context *keys = (struct MD5Context *)handle; + struct hmacmd5_context *ctx = FROMFIELD(mac, struct hmacmd5_context, mac); struct MD5Context s; unsigned char intermediate[16]; - s = keys[2]; /* structure copy */ + s = ctx->md5[2]; /* structure copy */ BinarySink_COPIED(&s); MD5Final(intermediate, &s); - s = keys[1]; /* structure copy */ + s = ctx->md5[1]; /* structure copy */ BinarySink_COPIED(&s); put_data(&s, intermediate, 16); MD5Final(hmac, &s); + smemclr(intermediate, sizeof(intermediate)); } -static int hmacmd5_verresult(void *handle, unsigned char const *hmac) +void hmacmd5_do_hmac(struct hmacmd5_context *ctx, + unsigned char const *blk, int len, unsigned char *hmac) { - unsigned char correct[16]; - hmacmd5_genresult(handle, correct); - return smemeq(correct, hmac, 16); + ssh2_mac_start(&ctx->mac); + put_data(&ctx->mac, blk, len); + return ssh2_mac_genresult(&ctx->mac, hmac); } -static void hmacmd5_do_hmac_internal(void *handle, - unsigned char const *blk, int len, - unsigned char const *blk2, int len2, - unsigned char *hmac) -{ - BinarySink *bs = hmacmd5_sink(handle); - hmacmd5_start(handle); - put_data(bs, blk, len); - if (blk2) put_data(bs, blk2, len2); - hmacmd5_genresult(handle, hmac); -} - -void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len, - unsigned char *hmac) -{ - hmacmd5_do_hmac_internal(handle, blk, len, NULL, 0, hmac); -} - -static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len, - unsigned long seq, unsigned char *hmac) -{ - unsigned char seqbuf[16]; - - PUT_32BIT_MSB_FIRST(seqbuf, seq); - hmacmd5_do_hmac_internal(handle, seqbuf, 4, blk, len, hmac); -} - -static void hmacmd5_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - hmacmd5_do_hmac_ssh(handle, blk, len, seq, blk + len); -} - -static int hmacmd5_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[16]; - hmacmd5_do_hmac_ssh(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 16); -} - -const struct ssh_mac ssh_hmac_md5 = { - hmacmd5_make_context, hmacmd5_free_context, hmacmd5_key_16, - hmacmd5_generate, hmacmd5_verify, - hmacmd5_start, hmacmd5_sink, hmacmd5_genresult, hmacmd5_verresult, +const struct ssh2_macalg ssh_hmac_md5 = { + hmacmd5_ssh2_new, hmacmd5_ssh2_free, hmacmd5_ssh2_setkey, + hmacmd5_start, hmacmd5_genresult, "hmac-md5", "hmac-md5-etm@openssh.com", 16, 16, "HMAC-MD5" diff --git a/sshsh256.c b/sshsh256.c index 51788679..e4b14fd7 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -256,111 +256,80 @@ const struct ssh_hash ssh_sha256 = { * HMAC wrapper on it. */ -static void *sha256_make_context(ssh2_cipher *cipher) +struct hmacsha256 { + SHA256_State sha[3]; + ssh2_mac mac; +}; + +static ssh2_mac *hmacsha256_new( + const struct ssh2_macalg *alg, ssh2_cipher *cipher) { - return snewn(3, SHA256_State); + struct hmacsha256 *ctx = snew(struct hmacsha256); + ctx->mac.vt = alg; + BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->sha[2]); + return &ctx->mac; } -static void sha256_free_context(void *handle) +static void hmacsha256_free(ssh2_mac *mac) { - smemclr(handle, 3 * sizeof(SHA256_State)); - sfree(handle); + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } -static void sha256_key_internal(void *handle, +static void sha256_key_internal(struct hmacsha256 *ctx, const unsigned char *key, int len) { - SHA256_State *keys = (SHA256_State *)handle; unsigned char foo[64]; int i; memset(foo, 0x36, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - SHA256_Init(&keys[0]); - put_data(&keys[0], foo, 64); + SHA256_Init(&ctx->sha[0]); + put_data(&ctx->sha[0], foo, 64); memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; - SHA256_Init(&keys[1]); - put_data(&keys[1], foo, 64); + SHA256_Init(&ctx->sha[1]); + put_data(&ctx->sha[1], foo, 64); smemclr(foo, 64); /* burn the evidence */ } -static void sha256_key(void *handle, const void *key) +static void hmacsha256_key(ssh2_mac *mac, const void *key) { - sha256_key_internal(handle, key, 32); + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); + sha256_key_internal(ctx, key, ctx->mac.vt->keylen); } -static void hmacsha256_start(void *handle) +static void hmacsha256_start(ssh2_mac *mac) { - SHA256_State *keys = (SHA256_State *)handle; + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); - keys[2] = keys[0]; /* structure copy */ - BinarySink_COPIED(&keys[2]); + ctx->sha[2] = ctx->sha[0]; /* structure copy */ + BinarySink_COPIED(&ctx->sha[2]); } -static BinarySink *hmacsha256_sink(void *handle) +static void hmacsha256_genresult(ssh2_mac *mac, unsigned char *hmac) { - SHA256_State *keys = (SHA256_State *)handle; - return BinarySink_UPCAST(&keys[2]); -} - -static void hmacsha256_genresult(void *handle, unsigned char *hmac) -{ - SHA256_State *keys = (SHA256_State *)handle; + struct hmacsha256 *ctx = FROMFIELD(mac, struct hmacsha256, mac); SHA256_State s; unsigned char intermediate[32]; - s = keys[2]; /* structure copy */ + s = ctx->sha[2]; /* structure copy */ BinarySink_COPIED(&s); SHA256_Final(&s, intermediate); - s = keys[1]; /* structure copy */ + s = ctx->sha[1]; /* structure copy */ BinarySink_COPIED(&s); put_data(&s, intermediate, 32); SHA256_Final(&s, hmac); } -static void sha256_do_hmac(void *handle, const unsigned char *blk, int len, - unsigned long seq, unsigned char *hmac) -{ - BinarySink *bs = hmacsha256_sink(handle); - hmacsha256_start(handle); - put_uint32(bs, seq); - put_data(bs, blk, len); - hmacsha256_genresult(handle, hmac); -} - -static void sha256_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - sha256_do_hmac(handle, blk, len, seq, blk + len); -} - -static int hmacsha256_verresult(void *handle, unsigned char const *hmac) -{ - unsigned char correct[32]; - hmacsha256_genresult(handle, correct); - return smemeq(correct, hmac, 32); -} - -static int sha256_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[32]; - sha256_do_hmac(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 32); -} - -const struct ssh_mac ssh_hmac_sha256 = { - sha256_make_context, sha256_free_context, sha256_key, - sha256_generate, sha256_verify, - hmacsha256_start, hmacsha256_sink, - hmacsha256_genresult, hmacsha256_verresult, +const struct ssh2_macalg ssh_hmac_sha256 = { + hmacsha256_new, hmacsha256_free, hmacsha256_key, + hmacsha256_start, hmacsha256_genresult, "hmac-sha2-256", "hmac-sha2-256-etm@openssh.com", 32, 32, "HMAC-SHA-256" diff --git a/sshsha.c b/sshsha.c index e2f2a860..310241a4 100644 --- a/sshsha.c +++ b/sshsha.c @@ -283,20 +283,30 @@ const struct ssh_hash ssh_sha1 = { * HMAC wrapper on it. */ -static void *sha1_make_context(ssh2_cipher *cipher) +struct hmacsha1 { + SHA_State sha[3]; + ssh2_mac mac; +}; + +static ssh2_mac *hmacsha1_new( + const struct ssh2_macalg *alg, ssh2_cipher *cipher) { - return snewn(3, SHA_State); + struct hmacsha1 *ctx = snew(struct hmacsha1); + ctx->mac.vt = alg; + BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->sha[2]); + return &ctx->mac; } -static void sha1_free_context(void *handle) +static void hmacsha1_free(ssh2_mac *mac) { - smemclr(handle, 3 * sizeof(SHA_State)); - sfree(handle); + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + smemclr(ctx, sizeof(*ctx)); + sfree(ctx); } -static void sha1_key_internal(void *handle, const unsigned char *key, int len) +static void sha1_key_internal(SHA_State *keys, + const unsigned char *key, int len) { - SHA_State *keys = (SHA_State *)handle; unsigned char foo[64]; int i; @@ -315,108 +325,38 @@ static void sha1_key_internal(void *handle, const unsigned char *key, int len) smemclr(foo, 64); /* burn the evidence */ } -static void sha1_key(void *handle, const void *key) +static void hmacsha1_key(ssh2_mac *mac, const void *key) { - sha1_key_internal(handle, key, 20); + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + /* Reading the key length out of the ssh2_macalg structure means + * this same method can be used for the _buggy variants which use + * a shorter key */ + sha1_key_internal(ctx->sha, key, ctx->mac.vt->keylen); } -static void sha1_key_buggy(void *handle, const void *key) +static void hmacsha1_start(ssh2_mac *mac) { - sha1_key_internal(handle, key, 16); + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); + + ctx->sha[2] = ctx->sha[0]; /* structure copy */ + BinarySink_COPIED(&ctx->sha[2]); } -static void hmacsha1_start(void *handle) +static void hmacsha1_genresult(ssh2_mac *mac, unsigned char *hmac) { - SHA_State *keys = (SHA_State *)handle; - - keys[2] = keys[0]; /* structure copy */ - BinarySink_COPIED(&keys[2]); -} - -static BinarySink *hmacsha1_sink(void *handle) -{ - SHA_State *keys = (SHA_State *)handle; - return BinarySink_UPCAST(&keys[2]); -} - -static void hmacsha1_genresult(void *handle, unsigned char *hmac) -{ - SHA_State *keys = (SHA_State *)handle; + struct hmacsha1 *ctx = FROMFIELD(mac, struct hmacsha1, mac); SHA_State s; unsigned char intermediate[20]; - s = keys[2]; /* structure copy */ + s = ctx->sha[2]; /* structure copy */ BinarySink_COPIED(&s); SHA_Final(&s, intermediate); - s = keys[1]; /* structure copy */ + s = ctx->sha[1]; /* structure copy */ BinarySink_COPIED(&s); put_data(&s, intermediate, 20); - SHA_Final(&s, hmac); -} - -static void sha1_do_hmac(void *handle, const unsigned char *blk, int len, - unsigned long seq, unsigned char *hmac) -{ - BinarySink *bs = hmacsha1_sink(handle); - hmacsha1_start(handle); - put_uint32(bs, seq); - put_data(bs, blk, len); - hmacsha1_genresult(handle, hmac); -} - -static void sha1_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - sha1_do_hmac(handle, blk, len, seq, blk + len); -} - -static int hmacsha1_verresult(void *handle, unsigned char const *hmac) -{ - unsigned char correct[20]; - hmacsha1_genresult(handle, correct); - return smemeq(correct, hmac, 20); -} - -static int sha1_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[20]; - sha1_do_hmac(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 20); -} - -static void hmacsha1_96_genresult(void *handle, unsigned char *hmac) -{ - unsigned char full[20]; - hmacsha1_genresult(handle, full); - memcpy(hmac, full, 12); -} - -static void sha1_96_generate(void *handle, void *vblk, int len, - unsigned long seq) -{ - unsigned char *blk = (unsigned char *)vblk; - unsigned char full[20]; - sha1_do_hmac(handle, blk, len, seq, full); - memcpy(blk + len, full, 12); -} - -static int hmacsha1_96_verresult(void *handle, unsigned char const *hmac) -{ - unsigned char correct[20]; - hmacsha1_genresult(handle, correct); - return smemeq(correct, hmac, 12); -} - -static int sha1_96_verify(void *handle, const void *vblk, int len, - unsigned long seq) -{ - const unsigned char *blk = (const unsigned char *)vblk; - unsigned char correct[20]; - sha1_do_hmac(handle, blk, len, seq, correct); - return smemeq(correct, blk + len, 12); + SHA_Final(&s, intermediate); + memcpy(hmac, intermediate, ctx->mac.vt->len); + smemclr(intermediate, sizeof(intermediate)); } void hmac_sha1_simple(void *key, int keylen, void *data, int datalen, @@ -432,39 +372,33 @@ void hmac_sha1_simple(void *key, int keylen, void *data, int datalen, SHA_Final(&states[1], output); } -const struct ssh_mac ssh_hmac_sha1 = { - sha1_make_context, sha1_free_context, sha1_key, - sha1_generate, sha1_verify, - hmacsha1_start, hmacsha1_sink, hmacsha1_genresult, hmacsha1_verresult, +const struct ssh2_macalg ssh_hmac_sha1 = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1", "hmac-sha1-etm@openssh.com", 20, 20, "HMAC-SHA1" }; -const struct ssh_mac ssh_hmac_sha1_96 = { - sha1_make_context, sha1_free_context, sha1_key, - sha1_96_generate, sha1_96_verify, - hmacsha1_start, hmacsha1_sink, - hmacsha1_96_genresult, hmacsha1_96_verresult, +const struct ssh2_macalg ssh_hmac_sha1_96 = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1-96", "hmac-sha1-96-etm@openssh.com", 12, 20, "HMAC-SHA1-96" }; -const struct ssh_mac ssh_hmac_sha1_buggy = { - sha1_make_context, sha1_free_context, sha1_key_buggy, - sha1_generate, sha1_verify, - hmacsha1_start, hmacsha1_sink, hmacsha1_genresult, hmacsha1_verresult, +const struct ssh2_macalg ssh_hmac_sha1_buggy = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1", NULL, 20, 16, "bug-compatible HMAC-SHA1" }; -const struct ssh_mac ssh_hmac_sha1_96_buggy = { - sha1_make_context, sha1_free_context, sha1_key_buggy, - sha1_96_generate, sha1_96_verify, - hmacsha1_start, hmacsha1_sink, - hmacsha1_96_genresult, hmacsha1_96_verresult, +const struct ssh2_macalg ssh_hmac_sha1_96_buggy = { + hmacsha1_new, hmacsha1_free, hmacsha1_key, + hmacsha1_start, hmacsha1_genresult, "hmac-sha1-96", NULL, 12, 16, "bug-compatible HMAC-SHA1-96"