SSH CRC attack detector now uses a dynamically allocated context.
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 25 Oct 2002 12:58:21 +0000 (12:58 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 25 Oct 2002 12:58:21 +0000 (12:58 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/putty@2132 cda61777-01e9-0310-a592-d414129be87e

ssh.c
ssh.h
sshcrcda.c

diff --git a/ssh.c b/ssh.c
index 9689fd2..677ff87 100644 (file)
--- a/ssh.c
+++ b/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;
diff --git a/ssh.h b/ssh.h
index 28dd6dd..bf57b8f 100644 (file)
--- a/ssh.h
+++ b/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];
index 7b683be..2821020 100644 (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 */
 }