From ef0c2e123fdbaecd4a3b89127b9852874dea700b Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 13 Jan 2012 22:59:45 +1100 Subject: [PATCH] defatal cipher.[ch] unbreak arcfour(128|256) --- ssh/authfile.c | 30 +++++--- ssh/cipher.c | 202 +++++++++++++++++++++++++++---------------------- ssh/cipher.h | 45 ++++++----- ssh/packet.c | 95 +++++++++++++++-------- ssh/packet.h | 3 + 5 files changed, 219 insertions(+), 156 deletions(-) diff --git a/ssh/authfile.c b/ssh/authfile.c index d7e8bc6..ef239ba 100644 --- a/ssh/authfile.c +++ b/ssh/authfile.c @@ -83,7 +83,7 @@ key_private_rsa1_to_blob(struct sshkey *key, Buffer *blob, { Buffer buffer, encrypted; u_char buf[100], *cp; - int i, cipher_num; + int r, i, cipher_num; CipherContext ciphercontext; Cipher *cipher; u_int32_t rnd; @@ -143,11 +143,14 @@ key_private_rsa1_to_blob(struct sshkey *key, Buffer *blob, /* Allocate space for the private part of the key in the buffer. */ cp = buffer_append_space(&encrypted, buffer_len(&buffer)); - cipher_set_key_string(&ciphercontext, cipher, passphrase, - CIPHER_ENCRYPT); - cipher_crypt(&ciphercontext, cp, - buffer_ptr(&buffer), buffer_len(&buffer)); - cipher_cleanup(&ciphercontext); + if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, + CIPHER_ENCRYPT)) != 0) + fatal("%s: cipher_set_key_string: %s", __func__, ssh_err(r)); + if ((r = cipher_crypt(&ciphercontext, cp, + buffer_ptr(&buffer), buffer_len(&buffer))) != 0) + fatal("%s: cipher_crypt: %s", __func__, ssh_err(r)); + if ((r = cipher_cleanup(&ciphercontext)) != 0) + fatal("%s: cipher_cleanup: %s", __func__, ssh_err(r)); memset(&ciphercontext, 0, sizeof(ciphercontext)); /* Destroy temporary data. */ @@ -410,7 +413,7 @@ key_load_public_type(int type, const char *filename, char **commentp) static struct sshkey * key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) { - int check1, check2, cipher_type; + int r, check1, check2, cipher_type; Buffer decrypted; u_char *cp; CipherContext ciphercontext; @@ -467,11 +470,14 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) cp = buffer_append_space(&decrypted, buffer_len(©)); /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ - cipher_set_key_string(&ciphercontext, cipher, passphrase, - CIPHER_DECRYPT); - cipher_crypt(&ciphercontext, cp, - buffer_ptr(©), buffer_len(©)); - cipher_cleanup(&ciphercontext); + if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, + CIPHER_DECRYPT)) != 0) + fatal("%s: cipher_set_key_string: %s", __func__, ssh_err(r)); + if ((r = cipher_crypt(&ciphercontext, cp, + buffer_ptr(©), buffer_len(©))) != 0) + fatal("%s: cipher_crypt: %s", __func__, ssh_err(r)); + if ((r = cipher_cleanup(&ciphercontext)) != 0) + fatal("%s: cipher_cleanup: %s", __func__, ssh_err(r)); memset(&ciphercontext, 0, sizeof(ciphercontext)); buffer_free(©); diff --git a/ssh/cipher.c b/ssh/cipher.c index 3acc418..4742770 100644 --- a/ssh/cipher.c +++ b/ssh/cipher.c @@ -42,8 +42,7 @@ #include #include -#include "xmalloc.h" -#include "log.h" +#include "err.h" #include "cipher.h" extern const EVP_CIPHER *evp_ssh1_bf(void); @@ -52,7 +51,7 @@ extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); extern const EVP_CIPHER *evp_aes_128_ctr(void); extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); -struct Cipher { +struct sshcipher { char *name; int number; /* for ssh1 only */ u_int block_size; @@ -88,25 +87,25 @@ struct Cipher { /*--*/ u_int -cipher_blocksize(const Cipher *c) +cipher_blocksize(const struct sshcipher *c) { return (c->block_size); } u_int -cipher_keylen(const Cipher *c) +cipher_keylen(const struct sshcipher *c) { return (c->key_len); } u_int -cipher_get_number(const Cipher *c) +cipher_get_number(const struct sshcipher *c) { return (c->number); } u_int -cipher_is_cbc(const Cipher *c) +cipher_is_cbc(const struct sshcipher *c) { return (c->cbc_mode); } @@ -123,20 +122,20 @@ cipher_mask_ssh1(int client) return mask; } -Cipher * +struct sshcipher * cipher_by_name(const char *name) { - Cipher *c; + struct sshcipher *c; for (c = ciphers; c->name != NULL; c++) if (strcmp(c->name, name) == 0) return c; return NULL; } -Cipher * +struct sshcipher * cipher_by_number(int id) { - Cipher *c; + struct sshcipher *c; for (c = ciphers; c->name != NULL; c++) if (c->number == id) return c; @@ -147,26 +146,23 @@ cipher_by_number(int id) int ciphers_valid(const char *names) { - Cipher *c; + struct sshcipher *c; char *cipher_list, *cp; char *p; if (names == NULL || strcmp(names, "") == 0) return 0; - cipher_list = cp = xstrdup(names); + if ((cipher_list = cp = strdup(names)) == NULL) + return 0; for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; (p = strsep(&cp, CIPHER_SEP))) { c = cipher_by_name(p); if (c == NULL || c->number != SSH_CIPHER_SSH2) { - debug("bad cipher %s [%s]", p, names); - xfree(cipher_list); + free(cipher_list); return 0; - } else { - debug3("cipher ok: %s [%s]", p, names); } } - debug3("ciphers ok: [%s]", names); - xfree(cipher_list); + free(cipher_list); return 1; } @@ -178,7 +174,7 @@ ciphers_valid(const char *names) int cipher_number(const char *name) { - Cipher *c; + struct sshcipher *c; if (name == NULL) return -1; for (c = ciphers; c->name != NULL; c++) @@ -190,117 +186,136 @@ cipher_number(const char *name) char * cipher_name(int id) { - Cipher *c = cipher_by_number(id); + struct sshcipher *c = cipher_by_number(id); return (c==NULL) ? "" : c->name; } -void -cipher_init(CipherContext *cc, Cipher *cipher, +const char * +cipher_warning_message(struct sshcipher_ctx *cc) +{ + if (cc == NULL || cc->cipher == NULL) + return NULL; + if (cc->cipher->number == SSH_CIPHER_DES) + return "use of DES is strongly discouraged due to " + "cryptographic weaknesses"; + return NULL; +} + +int +cipher_init(struct sshcipher_ctx *cc, struct sshcipher *cipher, const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, int do_encrypt) { - static int dowarn = 1; + int ret = SSH_ERR_INTERNAL_ERROR; const EVP_CIPHER *type; int klen; u_char *junk, *discard; if (cipher->number == SSH_CIPHER_DES) { - if (dowarn) { - error("Warning: use of DES is strongly discouraged " - "due to cryptographic weaknesses"); - dowarn = 0; - } if (keylen > 8) keylen = 8; } cc->plaintext = (cipher->number == SSH_CIPHER_NONE); - if (keylen < cipher->key_len) - fatal("cipher_init: key length %d is insufficient for %s.", - keylen, cipher->name); - if (iv != NULL && ivlen < cipher->block_size) - fatal("cipher_init: iv length %d is insufficient for %s.", - ivlen, cipher->name); + if (keylen < cipher->key_len || + (iv != NULL && ivlen < cipher->block_size)) + return SSH_ERR_INVALID_ARGUMENT; + cc->cipher = cipher; - type = (*cipher->evptype)(); - EVP_CIPHER_CTX_init(&cc->evp); if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, - (do_encrypt == CIPHER_ENCRYPT)) == 0) - fatal("cipher_init: EVP_CipherInit failed for %s", - cipher->name); + (do_encrypt == CIPHER_ENCRYPT)) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + bad: + EVP_CIPHER_CTX_cleanup(&cc->evp); + return ret; + } klen = EVP_CIPHER_CTX_key_length(&cc->evp); if (klen > 0 && keylen != (u_int)klen) { - debug2("cipher_init: set keylen (%d -> %d)", klen, keylen); - if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) - fatal("cipher_init: set keylen failed (%d -> %d)", - klen, keylen); + if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto bad; + } + } + if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto bad; } - if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) - fatal("cipher_init: EVP_CipherInit: set key failed for %s", - cipher->name); if (cipher->discard_len > 0) { - junk = xmalloc(cipher->discard_len); - discard = xmalloc(cipher->discard_len); - if (EVP_Cipher(&cc->evp, discard, junk, - cipher->discard_len) == 0) - fatal("evp_crypt: EVP_Cipher failed during discard"); - memset(discard, 0, cipher->discard_len); - xfree(junk); - xfree(discard); + if ((junk = malloc(cipher->discard_len)) == NULL || + (discard = malloc(cipher->discard_len)) == NULL) { + if (junk != NULL) + free(junk); + ret = SSH_ERR_ALLOC_FAIL; + goto bad; + } + ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len); + bzero(discard, cipher->discard_len); + free(junk); + free(discard); + if (ret != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto bad; + } } + return 0; } -void -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +int +cipher_crypt(struct sshcipher_ctx *cc, u_char *dest, + const u_char *src, u_int len) { if (len % cc->cipher->block_size) - fatal("cipher_encrypt: bad plaintext length %d", len); + return SSH_ERR_INVALID_ARGUMENT; if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0) - fatal("evp_crypt: EVP_Cipher failed"); + return SSH_ERR_LIBCRYPTO_ERROR; + return 0; } -void -cipher_cleanup(CipherContext *cc) +int +cipher_cleanup(struct sshcipher_ctx *cc) { if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) - error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); + return SSH_ERR_LIBCRYPTO_ERROR; + return 0; } /* * Selects the cipher, and keys if by computing the MD5 checksum of the * passphrase and using the resulting 16 bytes as the key. */ - -void -cipher_set_key_string(CipherContext *cc, Cipher *cipher, - const char *passphrase, int do_encrypt) +int +cipher_set_key_string(struct sshcipher_ctx *cc, struct sshcipher *cipher, + const char *pphrase, int do_encrypt) { MD5_CTX md; u_char digest[16]; + int ret = SSH_ERR_LIBCRYPTO_ERROR; - MD5_Init(&md); - MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase)); - MD5_Final(digest, &md); + if (MD5_Init(&md) != 1 || + MD5_Update(&md, (const u_char *)pphrase, strlen(pphrase)) != 1 || + MD5_Final(digest, &md) != 1) + goto out; - cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); + ret = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); + out: memset(digest, 0, sizeof(digest)); memset(&md, 0, sizeof(md)); + return ret; } /* - * Exports an IV from the CipherContext required to export the key + * Exports an IV from the sshcipher_ctx required to export the key * state back from the unprivileged child to the privileged parent * process. */ - int -cipher_get_keyiv_len(const CipherContext *cc) +cipher_get_keyiv_len(const struct sshcipher_ctx *cc) { - Cipher *c = cc->cipher; + struct sshcipher *c = cc->cipher; int ivlen; if (c->number == SSH_CIPHER_3DES) @@ -310,10 +325,10 @@ cipher_get_keyiv_len(const CipherContext *cc) return (ivlen); } -void -cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) +int +cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len) { - Cipher *c = cc->cipher; + struct sshcipher *c = cc->cipher; int evplen; switch (c->number) { @@ -321,11 +336,12 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); - if (evplen <= 0) - return; + if (evplen == 0) + break; + else if (evplen < 0) + return SSH_ERR_LIBCRYPTO_ERROR; if ((u_int)evplen != len) - fatal("%s: wrong iv length %d != %d", __func__, - evplen, len); + return SSH_ERR_INVALID_ARGUMENT; if (c->evptype == evp_aes_128_ctr) ssh_aes_ctr_iv(&cc->evp, 0, iv, len); else @@ -335,14 +351,15 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) ssh1_3des_iv(&cc->evp, 0, iv, 24); break; default: - fatal("%s: bad cipher %d", __func__, c->number); + return SSH_ERR_INVALID_ARGUMENT; } + return 0; } -void -cipher_set_keyiv(CipherContext *cc, u_char *iv) +int +cipher_set_keyiv(struct sshcipher_ctx *cc, u_char *iv) { - Cipher *c = cc->cipher; + struct sshcipher *c = cc->cipher; int evplen = 0; switch (c->number) { @@ -350,8 +367,8 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv) case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); - if (evplen == 0) - return; + if (evplen <= 0) + return SSH_ERR_LIBCRYPTO_ERROR; if (c->evptype == evp_aes_128_ctr) ssh_aes_ctr_iv(&cc->evp, 1, iv, evplen); else @@ -361,17 +378,18 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv) ssh1_3des_iv(&cc->evp, 1, iv, 24); break; default: - fatal("%s: bad cipher %d", __func__, c->number); + return SSH_ERR_INVALID_ARGUMENT; } + return 0; } #define EVP_X_STATE(evp) (evp).cipher_data #define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size int -cipher_get_keycontext(const CipherContext *cc, u_char *dat) +cipher_get_keycontext(const struct sshcipher_ctx *cc, u_char *dat) { - Cipher *c = cc->cipher; + struct sshcipher *c = cc->cipher; int plen = 0; if (c->evptype == EVP_rc4 || c->evptype == EVP_acss) { @@ -384,9 +402,9 @@ cipher_get_keycontext(const CipherContext *cc, u_char *dat) } void -cipher_set_keycontext(CipherContext *cc, u_char *dat) +cipher_set_keycontext(struct sshcipher_ctx *cc, u_char *dat) { - Cipher *c = cc->cipher; + struct sshcipher *c = cc->cipher; int plen; if (c->evptype == EVP_rc4 || c->evptype == EVP_acss) { diff --git a/ssh/cipher.h b/ssh/cipher.h index 3dd2270..a17cd3b 100644 --- a/ssh/cipher.h +++ b/ssh/cipher.h @@ -37,7 +37,9 @@ #ifndef CIPHER_H #define CIPHER_H +#include #include + /* * Cipher types for SSH-1. New types can be added, but old types should not * be removed for compatibility. The maximum allowed value is 31. @@ -58,35 +60,38 @@ #define CIPHER_ENCRYPT 1 #define CIPHER_DECRYPT 0 -typedef struct Cipher Cipher; -typedef struct CipherContext CipherContext; +typedef struct sshcipher Cipher; +typedef struct sshcipher_ctx CipherContext; -struct Cipher; -struct CipherContext { +struct sshcipher; +struct sshcipher_ctx { int plaintext; EVP_CIPHER_CTX evp; Cipher *cipher; }; u_int cipher_mask_ssh1(int); -Cipher *cipher_by_name(const char *); -Cipher *cipher_by_number(int); +struct sshcipher *cipher_by_name(const char *); +struct sshcipher *cipher_by_number(int); int cipher_number(const char *); char *cipher_name(int); int ciphers_valid(const char *); -void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, - const u_char *, u_int, int); -void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int); -void cipher_cleanup(CipherContext *); -void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); -u_int cipher_blocksize(const Cipher *); -u_int cipher_keylen(const Cipher *); -u_int cipher_is_cbc(const Cipher *); +int cipher_init(struct sshcipher_ctx *, struct sshcipher *, + const u_char *, u_int, const u_char *, u_int, int); +const char* cipher_warning_message(struct sshcipher_ctx *); +int cipher_crypt(struct sshcipher_ctx *, u_char *, const u_char *, u_int); +int cipher_cleanup(struct sshcipher_ctx *); +int cipher_set_key_string(struct sshcipher_ctx *, struct sshcipher *, + const char *, int); +u_int cipher_blocksize(const struct sshcipher *); +u_int cipher_keylen(const struct sshcipher *); +u_int cipher_is_cbc(const struct sshcipher *); + +u_int cipher_get_number(const struct sshcipher *); +int cipher_get_keyiv(struct sshcipher_ctx *, u_char *, u_int); +int cipher_set_keyiv(struct sshcipher_ctx *, u_char *); +int cipher_get_keyiv_len(const struct sshcipher_ctx *); +int cipher_get_keycontext(const struct sshcipher_ctx *, u_char *); +void cipher_set_keycontext(struct sshcipher_ctx *, u_char *); -u_int cipher_get_number(const Cipher *); -void cipher_get_keyiv(CipherContext *, u_char *, u_int); -void cipher_set_keyiv(CipherContext *, u_char *); -int cipher_get_keyiv_len(const CipherContext *); -int cipher_get_keycontext(const CipherContext *, u_char *); -void cipher_set_keycontext(CipherContext *, u_char *); #endif /* CIPHER_H */ diff --git a/ssh/packet.c b/ssh/packet.c index 7e9aee6..d30d8e2 100644 --- a/ssh/packet.c +++ b/ssh/packet.c @@ -245,9 +245,10 @@ ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) { struct session_state *state; Cipher *none = cipher_by_name("none"); + int r; if (none == NULL) - fatal("packet_set_connection: cannot load cipher 'none'"); + fatal("%s: cannot load cipher 'none'", __func__); if (ssh == NULL) ssh = ssh_alloc_session_state(); if (ssh == NULL) @@ -255,10 +256,11 @@ ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) state = ssh->state; state->connection_in = fd_in; state->connection_out = fd_out; - cipher_init(&state->send_context, none, (const u_char *)"", - 0, NULL, 0, CIPHER_ENCRYPT); - cipher_init(&state->receive_context, none, (const u_char *)"", - 0, NULL, 0, CIPHER_DECRYPT); + if ((r = cipher_init(&state->send_context, none, + (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 || + (r = cipher_init(&state->receive_context, none, + (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) + fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL; return ssh; @@ -359,13 +361,15 @@ ssh_packet_get_keyiv(struct ssh *ssh, int mode, u_char *iv, u_int len) { CipherContext *cc; + int r; if (mode == MODE_OUT) cc = &ssh->state->send_context; else cc = &ssh->state->receive_context; - cipher_get_keyiv(cc, iv, len); + if ((r = cipher_get_keyiv(cc, iv, len)) != 0) + fatal("%s: cipher_get_keyiv failed: %s", __func__, ssh_err(r)); } int @@ -411,13 +415,15 @@ void ssh_packet_set_iv(struct ssh *ssh, int mode, u_char *dat) { CipherContext *cc; + int r; if (mode == MODE_OUT) cc = &ssh->state->send_context; else cc = &ssh->state->receive_context; - cipher_set_keyiv(cc, dat); + if ((r = cipher_set_keyiv(cc, dat)) != 0) + fatal("%s: cipher_set_keyiv failed: %s", __func__, ssh_err(r)); } int @@ -505,6 +511,7 @@ void ssh_packet_close(struct ssh *ssh) { struct session_state *state = ssh->state; + int r; if (!state->initialized) return; @@ -524,8 +531,9 @@ ssh_packet_close(struct ssh *ssh) sshbuf_free(state->compression_buffer); buffer_compress_uninit(); } - cipher_cleanup(&state->send_context); - cipher_cleanup(&state->receive_context); + if ((r = cipher_cleanup(&state->send_context)) != 0 || + (r = cipher_cleanup(&state->receive_context)) != 0) + fatal("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); } /* Sets remote side protocol flags. */ @@ -580,19 +588,28 @@ ssh_packet_set_encryption_key(struct ssh *ssh, const u_char *key, u_int keylen, { struct session_state *state = ssh->state; Cipher *cipher = cipher_by_number(number); + int r; + const char *wmsg; if (cipher == NULL) - fatal("packet_set_encryption_key: unknown cipher number %d", number); + fatal("%s: unknown cipher number %d", __func__, number); if (keylen < 20) - fatal("packet_set_encryption_key: keylen too small: %d", keylen); + fatal("%s: keylen too small: %d", __func__, keylen); if (keylen > SSH_SESSION_KEY_LENGTH) - fatal("packet_set_encryption_key: keylen too big: %d", keylen); + fatal("%s: keylen too big: %d", __func__, keylen); memcpy(state->ssh1_key, key, keylen); state->ssh1_keylen = keylen; - cipher_init(&state->send_context, cipher, key, keylen, NULL, - 0, CIPHER_ENCRYPT); - cipher_init(&state->receive_context, cipher, key, keylen, NULL, - 0, CIPHER_DECRYPT); + if ((r = cipher_init(&state->send_context, cipher, key, keylen, + NULL, 0, CIPHER_ENCRYPT)) != 0 || + (r = cipher_init(&state->receive_context, cipher, key, keylen, + NULL, 0, CIPHER_DECRYPT) != 0)) + fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); + if (!ssh->cipher_warning_done && + ((wmsg = cipher_warning_message(&state->send_context)) != NULL || + (wmsg = cipher_warning_message(&state->send_context)) != NULL)) { + error("Warning: %s", wmsg); + ssh->cipher_warning_done = 1; + } } u_int @@ -707,7 +724,7 @@ ssh_packet_send1(struct ssh *ssh) { struct session_state *state = ssh->state; u_char buf[8], *cp; - int i, padding, len, r; + int r, i, padding, len; u_int checksum; u_int32_t rnd = 0; @@ -767,9 +784,10 @@ ssh_packet_send1(struct ssh *ssh) if ((r = sshbuf_reserve(state->output, sshbuf_len(state->outgoing_packet), &cp)) != 0) goto out; - cipher_crypt(&state->send_context, cp, + if ((r = cipher_crypt(&state->send_context, cp, sshbuf_ptr(state->outgoing_packet), - sshbuf_len(state->outgoing_packet)); + sshbuf_len(state->outgoing_packet))) != 0) + goto out; #ifdef PACKET_DEBUG fprintf(stderr, "encrypted: "); @@ -799,7 +817,8 @@ ssh_set_newkeys(struct ssh *ssh, int mode) Comp *comp; CipherContext *cc; u_int64_t *max_blocks; - int crypt_type; + int crypt_type, r; + const char *wmsg; debug2("set_newkeys: mode %d", mode); @@ -816,7 +835,9 @@ ssh_set_newkeys(struct ssh *ssh, int mode) } if (state->newkeys[mode] != NULL) { debug("set_newkeys: rekeying"); - cipher_cleanup(cc); + if ((r = cipher_cleanup(cc)) != 0) + fatal("%s: cipher_cleanup failed: %s", + __func__, ssh_err(r)); enc = &state->newkeys[mode]->enc; mac = &state->newkeys[mode]->mac; comp = &state->newkeys[mode]->comp; @@ -838,8 +859,14 @@ ssh_set_newkeys(struct ssh *ssh, int mode) if (mac_init(mac) == 0) mac->enabled = 1; DBG(debug("cipher_init_context: %d", mode)); - cipher_init(cc, enc->cipher, enc->key, enc->key_len, - enc->iv, enc->block_size, crypt_type); + if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len, + enc->iv, enc->block_size, crypt_type)) != 0) + fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); + if (!ssh->cipher_warning_done && + (wmsg = cipher_warning_message(cc)) != NULL) { + error("Warning: %s", wmsg); + ssh->cipher_warning_done = 1; + } /* Deleting the keys does not gain extra security */ /* memset(enc->iv, 0, enc->block_size); memset(enc->key, 0, enc->key_len); @@ -915,7 +942,7 @@ ssh_packet_send2_wrapped(struct ssh *ssh) Enc *enc = NULL; Mac *mac = NULL; Comp *comp = NULL; - int block_size, r; + int r, block_size; if (state->newkeys[MODE_OUT] != NULL) { enc = &state->newkeys[MODE_OUT]->enc; @@ -1003,9 +1030,10 @@ ssh_packet_send2_wrapped(struct ssh *ssh) if ((r = sshbuf_reserve(state->output, sshbuf_len(state->outgoing_packet), &cp)) != 0) goto out; - cipher_crypt(&state->send_context, cp, + if ((r = cipher_crypt(&state->send_context, cp, sshbuf_ptr(state->outgoing_packet), - sshbuf_len(state->outgoing_packet)); + sshbuf_len(state->outgoing_packet))) != 0) + goto out; /* append unencrypted MAC */ if (mac && mac->enabled) if ((r = sshbuf_put(state->output, macbuf, mac->mac_len)) != 0) @@ -1287,8 +1315,9 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep) sshbuf_reset(state->incoming_packet); if ((r = sshbuf_reserve(state->incoming_packet, padded_len, &cp)) != 0) goto out; - cipher_crypt(&state->receive_context, cp, - sshbuf_ptr(state->input), padded_len); + if ((r = cipher_crypt(&state->receive_context, cp, + sshbuf_ptr(state->input), padded_len)) != 0) + goto out; if ((r = sshbuf_consume(state->input, padded_len)) != 0) goto out; @@ -1376,8 +1405,9 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) if ((r = sshbuf_reserve(state->incoming_packet, block_size, &cp)) != 0) goto out; - cipher_crypt(&state->receive_context, cp, - sshbuf_ptr(state->input), block_size); + if ((r = cipher_crypt(&state->receive_context, cp, + sshbuf_ptr(state->input), block_size)) != 0) + goto out; cp = sshbuf_ptr(state->incoming_packet); state->packlen = get_u32(cp); if (state->packlen < 1 + 4 || @@ -1417,8 +1447,9 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) #endif if ((r = sshbuf_reserve(state->incoming_packet, need, &cp)) != 0) goto out; - cipher_crypt(&state->receive_context, cp, - sshbuf_ptr(state->input), need); + if ((r = cipher_crypt(&state->receive_context, cp, + sshbuf_ptr(state->input), need)) != 0) + goto out; if ((r = sshbuf_consume(state->input, need)) != 0) goto out; /* diff --git a/ssh/packet.h b/ssh/packet.h index 0c8feb2..35f4848 100644 --- a/ssh/packet.h +++ b/ssh/packet.h @@ -62,6 +62,9 @@ struct ssh { /* Lists for private and public keys */ TAILQ_HEAD(, key_entry) private_keys; TAILQ_HEAD(, key_entry) public_keys; + + /* One-off warning about weak ciphers */ + int cipher_warning_done; }; struct ssh *ssh_alloc_session_state(void);