mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
SSH CRC attack detector now uses a dynamically allocated context.
[originally from svn r2132]
This commit is contained in:
parent
8f91f07599
commit
107d1d875d
8
ssh.c
8
ssh.c
@ -560,6 +560,7 @@ struct ssh_tag {
|
||||
int remote_bugs;
|
||||
const struct ssh_cipher *cipher;
|
||||
void *v1_cipher_ctx;
|
||||
void *crcda_ctx;
|
||||
const struct ssh2_cipher *cscipher, *sccipher;
|
||||
void *cs_cipher_ctx, *sc_cipher_ctx;
|
||||
const struct ssh_mac *csmac, *scmac;
|
||||
@ -809,7 +810,8 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
|
||||
st->to_read -= st->chunk;
|
||||
}
|
||||
|
||||
if (ssh->cipher && detect_attack(ssh->pktin.data, st->biglen, NULL)) {
|
||||
if (ssh->cipher && detect_attack(ssh->crcda_ctx, ssh->pktin.data,
|
||||
st->biglen, NULL)) {
|
||||
bombout(("Network attack (CRC compensation) detected!"));
|
||||
crReturn(0);
|
||||
}
|
||||
@ -2377,6 +2379,9 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
||||
logevent(buf);
|
||||
}
|
||||
|
||||
ssh->crcda_ctx = crcda_make_context();
|
||||
logevent("Installing CRC compensation attack detector");
|
||||
|
||||
crWaitUntil(ispkt);
|
||||
|
||||
if (ssh->pktin.type != SSH1_SMSG_SUCCESS) {
|
||||
@ -5801,6 +5806,7 @@ static char *ssh_init(void *frontend_handle, void **backend_handle,
|
||||
ssh->s = NULL;
|
||||
ssh->cipher = NULL;
|
||||
ssh->v1_cipher_ctx = NULL;
|
||||
ssh->crcda_ctx = NULL;
|
||||
ssh->cscipher = NULL;
|
||||
ssh->cs_cipher_ctx = NULL;
|
||||
ssh->sccipher = NULL;
|
||||
|
5
ssh.h
5
ssh.h
@ -75,7 +75,10 @@ unsigned long crc32(const void *s, size_t len);
|
||||
unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len);
|
||||
|
||||
/* SSH CRC compensation attack detector */
|
||||
int detect_attack(unsigned char *buf, uint32 len, unsigned char *IV);
|
||||
void *crcda_make_context(void);
|
||||
void crcda_free_context(void *handle);
|
||||
int detect_attack(void *handle, unsigned char *buf, uint32 len,
|
||||
unsigned char *IV);
|
||||
|
||||
typedef struct {
|
||||
uint32 h[4];
|
||||
|
52
sshcrcda.c
52
sshcrcda.c
@ -56,6 +56,24 @@ typedef unsigned short uint16;
|
||||
uchar ONE[4] = { 1, 0, 0, 0 };
|
||||
uchar ZERO[4] = { 0, 0, 0, 0 };
|
||||
|
||||
struct crcda_ctx {
|
||||
uint16 *h;
|
||||
uint32 n;
|
||||
};
|
||||
|
||||
void *crcda_make_context(void)
|
||||
{
|
||||
struct crcda_ctx *ret = smalloc(sizeof(struct crcda_ctx));
|
||||
ret->h = NULL;
|
||||
ret->n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void crcda_free_context(void *handle)
|
||||
{
|
||||
sfree(handle);
|
||||
}
|
||||
|
||||
static void crc_update(uint32 *a, void *b)
|
||||
{
|
||||
*a = crc32_update(*a, b, 4);
|
||||
@ -85,10 +103,9 @@ static int check_crc(uchar *S, uchar *buf, uint32 len, uchar *IV)
|
||||
}
|
||||
|
||||
/* Detect a crc32 compensation attack on a packet */
|
||||
int detect_attack(uchar *buf, uint32 len, uchar *IV)
|
||||
int detect_attack(void *handle, uchar *buf, uint32 len, uchar *IV)
|
||||
{
|
||||
static uint16 *h = (uint16 *) NULL;
|
||||
static uint32 n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
struct crcda_ctx *ctx = (struct crcda_ctx *)handle;
|
||||
register uint32 i, j;
|
||||
uint32 l;
|
||||
register uchar *c;
|
||||
@ -96,17 +113,16 @@ int detect_attack(uchar *buf, uint32 len, uchar *IV)
|
||||
|
||||
assert(!(len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0));
|
||||
for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
for (l = ctx->n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
;
|
||||
|
||||
if (h == NULL) {
|
||||
logevent("Installing CRC compensation attack detector");
|
||||
n = l;
|
||||
h = (uint16 *) smalloc(n * HASH_ENTRYSIZE);
|
||||
if (ctx->h == NULL) {
|
||||
ctx->n = l;
|
||||
ctx->h = (uint16 *) smalloc(ctx->n * HASH_ENTRYSIZE);
|
||||
} else {
|
||||
if (l > n) {
|
||||
n = l;
|
||||
h = (uint16 *) srealloc(h, n * HASH_ENTRYSIZE);
|
||||
if (l > ctx->n) {
|
||||
ctx->n = l;
|
||||
ctx->h = (uint16 *) srealloc(ctx->h, ctx->n * HASH_ENTRYSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,29 +145,29 @@ int detect_attack(uchar *buf, uint32 len, uchar *IV)
|
||||
}
|
||||
return 0; /* ok */
|
||||
}
|
||||
memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
|
||||
memset(ctx->h, HASH_UNUSEDCHAR, ctx->n * HASH_ENTRYSIZE);
|
||||
|
||||
if (IV)
|
||||
h[HASH(IV) & (n - 1)] = HASH_IV;
|
||||
ctx->h[HASH(IV) & (ctx->n - 1)] = HASH_IV;
|
||||
|
||||
for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
|
||||
for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (n - 1)) {
|
||||
if (h[i] == HASH_IV) {
|
||||
for (i = HASH(c) & (ctx->n - 1); ctx->h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (ctx->n - 1)) {
|
||||
if (ctx->h[i] == HASH_IV) {
|
||||
if (!CMP(c, IV)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return 1; /* attack detected */
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
|
||||
} else if (!CMP(c, buf + ctx->h[i] * SSH_BLOCKSIZE)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return 1; /* attack detected */
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
h[i] = j;
|
||||
ctx->h[i] = j;
|
||||
}
|
||||
return 0; /* ok */
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user