mirror of
https://github.com/openssh/libopenssh
synced 2026-04-16 09:45:53 +00:00
defatal cipher.[ch]
unbreak arcfour(128|256)
This commit is contained in:
committed by
Markus Friedl
parent
c037dfa962
commit
ef0c2e123f
@@ -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(©);
|
||||
|
||||
|
||||
202
ssh/cipher.c
202
ssh/cipher.c
@@ -42,8 +42,7 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#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) ? "<unknown>" : 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) {
|
||||
|
||||
45
ssh/cipher.h
45
ssh/cipher.h
@@ -37,7 +37,9 @@
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
95
ssh/packet.c
95
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;
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user