diff --git a/ssh/kex.h b/ssh/kex.h index da58d2d..b645d3b 100644 --- a/ssh/kex.h +++ b/ssh/kex.h @@ -27,9 +27,10 @@ #define KEX_H #include -#include #include +#include "mac.h" + #define KEX_COOKIE_LEN 16 #define KEX_DH1 "diffie-hellman-group1-sha1" @@ -76,7 +77,7 @@ enum kex_exchange { #define KEX_INIT_SENT 0x0001 typedef struct Kex Kex; -typedef struct Mac Mac; +typedef struct sshmac Mac; typedef struct Comp Comp; typedef struct Enc Enc; typedef struct Newkeys Newkeys; @@ -90,17 +91,6 @@ struct Enc { u_char *key; u_char *iv; }; -struct Mac { - char *name; - int enabled; - u_int mac_len; - u_char *key; - u_int key_len; - int type; - const EVP_MD *evp_md; - HMAC_CTX evp_ctx; - struct umac_ctx *umac_ctx; -}; struct Comp { int type; int enabled; diff --git a/ssh/mac.c b/ssh/mac.c index 1fdad87..279b246 100644 --- a/ssh/mac.c +++ b/ssh/mac.c @@ -38,6 +38,7 @@ #include "kex.h" #include "mac.h" #include "misc.h" +#include "err.h" #include "umac.h" @@ -66,7 +67,7 @@ struct { { NULL, 0, NULL, 0, -1, -1 } }; -static void +static int mac_setup_by_id(Mac *mac, int which) { int evp_len; @@ -74,7 +75,7 @@ mac_setup_by_id(Mac *mac, int which) if (mac->type == SSH_EVP) { mac->evp_md = (*macs[which].mdfunc)(); if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0) - fatal("mac %s len %d", mac->name, evp_len); + return SSH_ERR_LIBCRYPTO_ERROR; mac->key_len = mac->mac_len = (u_int)evp_len; } else { mac->mac_len = macs[which].len / 8; @@ -83,6 +84,7 @@ mac_setup_by_id(Mac *mac, int which) } if (macs[which].truncatebits != 0) mac->mac_len = macs[which].truncatebits / 8; + return 0; } int @@ -93,63 +95,72 @@ mac_setup(Mac *mac, char *name) for (i = 0; macs[i].name; i++) { if (strcmp(name, macs[i].name) == 0) { if (mac != NULL) - mac_setup_by_id(mac, i); - debug2("mac_setup: found %s", name); - return (0); + return mac_setup_by_id(mac, i); + return 0; } } - debug2("mac_setup: unknown %s", name); - return (-1); + return SSH_ERR_INVALID_ARGUMENT; } int mac_init(Mac *mac) { if (mac->key == NULL) - fatal("mac_init: no key"); + return SSH_ERR_INVALID_ARGUMENT; switch (mac->type) { case SSH_EVP: if (mac->evp_md == NULL) - return -1; + return SSH_ERR_INVALID_ARGUMENT; HMAC_CTX_init(&mac->evp_ctx); - HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, mac->evp_md); + if (HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, + mac->evp_md) != 1) { + HMAC_CTX_cleanup(&mac->evp_ctx); + return SSH_ERR_LIBCRYPTO_ERROR; + } return 0; case SSH_UMAC: - mac->umac_ctx = umac_new(mac->key); + if ((mac->umac_ctx = umac_new(mac->key)) == NULL) + return SSH_ERR_ALLOC_FAIL; return 0; default: - return -1; + return SSH_ERR_INVALID_ARGUMENT; } } -u_char * -mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) +int +mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen, + u_char *digest, size_t dlen) { - static u_char m[EVP_MAX_MD_SIZE]; + static u_char m[MAC_DIGEST_LEN_MAX]; u_char b[4], nonce[8]; if (mac->mac_len > sizeof(m)) - fatal("mac_compute: mac too long %u %lu", - mac->mac_len, (u_long)sizeof(m)); + return SSH_ERR_INTERNAL_ERROR; switch (mac->type) { case SSH_EVP: - put_u32(b, seqno); + POKE_U32(b, seqno); /* reset HMAC context */ - HMAC_Init(&mac->evp_ctx, NULL, 0, NULL); - HMAC_Update(&mac->evp_ctx, b, sizeof(b)); - HMAC_Update(&mac->evp_ctx, data, datalen); - HMAC_Final(&mac->evp_ctx, m, NULL); + if (HMAC_Init(&mac->evp_ctx, NULL, 0, NULL) != 1 || + HMAC_Update(&mac->evp_ctx, b, sizeof(b)) != 1 || + HMAC_Update(&mac->evp_ctx, data, datalen) != 1 || + HMAC_Final(&mac->evp_ctx, m, NULL) != 1) + return SSH_ERR_LIBCRYPTO_ERROR; break; case SSH_UMAC: - put_u64(nonce, seqno); + POKE_U64(nonce, seqno); umac_update(mac->umac_ctx, data, datalen); umac_final(mac->umac_ctx, m, nonce); break; default: - fatal("mac_compute: unknown MAC type"); + return SSH_ERR_INVALID_ARGUMENT; } - return (m); + if (digest != NULL) { + if (dlen > mac->mac_len) + dlen = mac->mac_len; + memcpy(digest, m, dlen); + } + return 0; } void @@ -172,19 +183,16 @@ mac_valid(const char *names) char *maclist, *cp, *p; if (names == NULL || strcmp(names, "") == 0) - return (0); - maclist = cp = xstrdup(names); + return 0; + if ((maclist = cp = xstrdup(names)) == NULL) + return 0; for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0'; (p = strsep(&cp, MAC_SEP))) { if (mac_setup(NULL, p) < 0) { - debug("bad mac %s [%s]", p, names); - xfree(maclist); - return (0); - } else { - debug3("mac ok: %s [%s]", p, names); + free(maclist); + return 0; } } - debug3("macs ok: [%s]", names); - xfree(maclist); - return (1); + free(maclist); + return 1; } diff --git a/ssh/mac.h b/ssh/mac.h index 39f564d..3fbd5a3 100644 --- a/ssh/mac.h +++ b/ssh/mac.h @@ -23,8 +23,32 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef SSHMAC_H +#define SSHMAC_H + +#include +#include +#include + +#define MAC_DIGEST_LEN_MAX EVP_MAX_MD_SIZE + +struct sshmac { + char *name; + int enabled; + u_int mac_len; + u_char *key; + u_int key_len; + int type; + const EVP_MD *evp_md; + HMAC_CTX evp_ctx; + struct umac_ctx *umac_ctx; +}; + int mac_valid(const char *); -int mac_setup(Mac *, char *); -int mac_init(Mac *); -u_char *mac_compute(Mac *, u_int32_t, u_char *, int); -void mac_clear(Mac *); +int mac_setup(struct sshmac *, char *); +int mac_init(struct sshmac *); +int mac_compute(struct sshmac *, u_int32_t, u_char *, int, + u_char *, size_t); +void mac_clear(struct sshmac *); + +#endif /* SSHMAC_H */ diff --git a/ssh/packet.c b/ssh/packet.c index d30d8e2..e2db616 100644 --- a/ssh/packet.c +++ b/ssh/packet.c @@ -298,8 +298,8 @@ ssh_packet_stop_discard(struct ssh *ssh) fatal("%s: %s", __func__, ssh_err(r)); (void) mac_compute(state->packet_discard_mac, state->p_read.seqnr, - sshbuf_ptr(state->incoming_packet), - PACKET_MAX_SIZE); + sshbuf_ptr(state->incoming_packet), PACKET_MAX_SIZE, + NULL, 0); } logit("Finished discarding for %.200s", get_remote_ipaddr()); cleanup_exit(255); @@ -856,8 +856,9 @@ ssh_set_newkeys(struct ssh *ssh, int mode) enc = &state->newkeys[mode]->enc; mac = &state->newkeys[mode]->mac; comp = &state->newkeys[mode]->comp; - if (mac_init(mac) == 0) - mac->enabled = 1; + if ((r = mac_init(mac)) != 0) + fatal("newkeys: mac_init_failed: %s", ssh_err(r)); + mac->enabled = 1; DBG(debug("cipher_init_context: %d", mode)); if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len, enc->iv, enc->block_size, crypt_type)) != 0) @@ -934,7 +935,7 @@ int ssh_packet_send2_wrapped(struct ssh *ssh) { struct session_state *state = ssh->state; - u_char type, *cp, *macbuf = NULL; + u_char type, *cp, macbuf[MAC_DIGEST_LEN_MAX]; u_char padlen, pad; u_int packet_length = 0; u_int i, len; @@ -1021,9 +1022,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh) /* compute MAC over seqnr and packet(length fields, payload, padding) */ if (mac && mac->enabled) { - macbuf = mac_compute(mac, state->p_send.seqnr, + if ((r = mac_compute(mac, state->p_send.seqnr, sshbuf_ptr(state->outgoing_packet), - sshbuf_len(state->outgoing_packet)); + sshbuf_len(state->outgoing_packet), + macbuf, sizeof(macbuf))) != 0) + goto out; DBG(debug("done calc MAC out #%d", state->p_send.seqnr)); } /* encrypt packet and append to output buffer. */ @@ -1374,7 +1377,7 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) { struct session_state *state = ssh->state; u_int padlen, need; - u_char *macbuf, *cp; + u_char macbuf[MAC_DIGEST_LEN_MAX], *cp; u_int maclen, block_size; Enc *enc = NULL; Mac *mac = NULL; @@ -1457,10 +1460,12 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) * increment sequence number for incoming packet */ if (mac && mac->enabled) { - macbuf = mac_compute(mac, state->p_read.seqnr, + if ((r = mac_compute(mac, state->p_read.seqnr, sshbuf_ptr(state->incoming_packet), - sshbuf_len(state->incoming_packet)); - if (timingsafe_bcmp(macbuf, sshbuf_ptr(state->input), + sshbuf_len(state->incoming_packet), + macbuf, sizeof(macbuf))) != 0) + goto out; + if (timingsafe_bcmp(macbuf, buffer_ptr(state->input), mac->mac_len) != 0) { logit("Corrupted MAC on input."); if (need > PACKET_MAX_SIZE) diff --git a/ssh/umac.c b/ssh/umac.c index 5a07048..9ddbd40 100644 --- a/ssh/umac.c +++ b/ssh/umac.c @@ -66,7 +66,6 @@ #include #include -#include "xmalloc.h" #include "umac.h" #include #include @@ -1197,7 +1196,7 @@ int umac_delete(struct umac_ctx *ctx) if (ctx) { if (ALLOC_BOUNDARY) ctx = (struct umac_ctx *)ctx->free_ptr; - xfree(ctx); + free(ctx); } return (1); } @@ -1213,7 +1212,7 @@ struct umac_ctx *umac_new(u_char key[]) size_t bytes_to_add; aes_int_key prf_key; - octx = ctx = xmalloc(sizeof(*ctx) + ALLOC_BOUNDARY); + octx = ctx = malloc(sizeof(*ctx) + ALLOC_BOUNDARY); if (ctx) { if (ALLOC_BOUNDARY) { bytes_to_add = ALLOC_BOUNDARY -