1
0
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:
Simon Tatham 2002-10-25 12:58:21 +00:00
parent 8f91f07599
commit 107d1d875d
3 changed files with 45 additions and 20 deletions

8
ssh.c
View File

@ -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
View File

@ -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];

View File

@ -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 */
}