[BACK]Return to deattack.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/deattack.c, Revision 1.29

1.29    ! deraadt     1: /* $OpenBSD: deattack.c,v 1.28 2006/07/22 20:48:23 stevesk Exp $ */
1.1       dugsong     2: /*
1.2       dugsong     3:  * Cryptographic attack detector for ssh - source code
                      4:  *
                      5:  * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
                      6:  *
                      7:  * All rights reserved. Redistribution and use in source and binary
                      8:  * forms, with or without modification, are permitted provided that
                      9:  * this copyright notice is retained.
                     10:  *
                     11:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
                     12:  * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
                     13:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
                     14:  * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
                     15:  * SOFTWARE.
                     16:  *
                     17:  * Ariel Futoransky <futo@core-sdi.com>
1.6       deraadt    18:  * <http://www.core-sdi.com>
                     19:  */
1.1       dugsong    20:
1.29    ! deraadt    21: #include <sys/types.h>
1.28      stevesk    22:
                     23: #include <string.h>
1.29    ! deraadt    24: #include <stdio.h>
        !            25: #include <stdarg.h>
1.18      stevesk    26:
1.29    ! deraadt    27: #include "xmalloc.h"
1.1       dugsong    28: #include "deattack.h"
1.12      markus     29: #include "log.h"
1.3       markus     30: #include "crc32.h"
1.27      djm        31: #include "misc.h"
1.1       dugsong    32:
                     33: /* SSH Constants */
1.5       markus     34: #define SSH_MAXBLOCKS  (32 * 1024)
                     35: #define SSH_BLOCKSIZE  (8)
1.1       dugsong    36:
                     37: /* Hashing constants */
1.5       markus     38: #define HASH_MINSIZE   (8 * 1024)
                     39: #define HASH_ENTRYSIZE (2)
                     40: #define HASH_FACTOR(x) ((x)*3/2)
                     41: #define HASH_UNUSEDCHAR        (0xff)
                     42: #define HASH_UNUSED    (0xffff)
1.17      deraadt    43: #define HASH_IV                (0xfffe)
1.1       dugsong    44:
1.5       markus     45: #define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
1.1       dugsong    46:
                     47:
                     48: /* Hash function (Input keys are cipher results) */
1.27      djm        49: #define HASH(x)                get_u32(x)
1.1       dugsong    50:
1.13      deraadt    51: #define CMP(a, b)      (memcmp(a, b, SSH_BLOCKSIZE))
1.1       dugsong    52:
1.14      itojun     53: static void
1.5       markus     54: crc_update(u_int32_t *a, u_int32_t b)
1.1       dugsong    55: {
1.5       markus     56:        b ^= *a;
1.22      deraadt    57:        *a = ssh_crc32((u_char *)&b, sizeof(b));
1.1       dugsong    58: }
                     59:
1.5       markus     60: /* detect if a block is used in a particular pattern */
1.14      itojun     61: static int
1.23      djm        62: check_crc(u_char *S, u_char *buf, u_int32_t len)
1.1       dugsong    63: {
1.5       markus     64:        u_int32_t crc;
1.11      markus     65:        u_char *c;
1.1       dugsong    66:
1.5       markus     67:        crc = 0;
                     68:        for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
                     69:                if (!CMP(S, c)) {
                     70:                        crc_update(&crc, 1);
                     71:                        crc_update(&crc, 0);
                     72:                } else {
                     73:                        crc_update(&crc, 0);
                     74:                        crc_update(&crc, 0);
                     75:                }
                     76:        }
                     77:        return (crc == 0);
1.1       dugsong    78: }
                     79:
                     80:
1.5       markus     81: /* Detect a crc32 compensation attack on a packet */
1.1       dugsong    82: int
1.23      djm        83: detect_attack(u_char *buf, u_int32_t len)
1.1       dugsong    84: {
1.5       markus     85:        static u_int16_t *h = (u_int16_t *) NULL;
1.10      markus     86:        static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
1.15      mpech      87:        u_int32_t i, j;
1.5       markus     88:        u_int32_t l;
1.15      mpech      89:        u_char *c;
1.11      markus     90:        u_char *d;
1.5       markus     91:
                     92:        if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
                     93:            len % SSH_BLOCKSIZE != 0) {
                     94:                fatal("detect_attack: bad length %d", len);
                     95:        }
                     96:        for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
                     97:                ;
1.1       dugsong    98:
1.5       markus     99:        if (h == NULL) {
                    100:                debug("Installing crc compensation attack detector.");
1.24      djm       101:                h = (u_int16_t *) xcalloc(l, HASH_ENTRYSIZE);
1.5       markus    102:                n = l;
                    103:        } else {
                    104:                if (l > n) {
1.25      djm       105:                        h = (u_int16_t *)xrealloc(h, l, HASH_ENTRYSIZE);
1.5       markus    106:                        n = l;
                    107:                }
                    108:        }
                    109:
                    110:        if (len <= HASH_MINBLOCKS) {
                    111:                for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
                    112:                        for (d = buf; d < c; d += SSH_BLOCKSIZE) {
                    113:                                if (!CMP(c, d)) {
1.23      djm       114:                                        if ((check_crc(c, buf, len)))
1.5       markus    115:                                                return (DEATTACK_DETECTED);
                    116:                                        else
                    117:                                                break;
                    118:                                }
                    119:                        }
                    120:                }
                    121:                return (DEATTACK_OK);
                    122:        }
                    123:        memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
                    124:
                    125:        for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
                    126:                for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
1.17      deraadt   127:                    i = (i + 1) & (n - 1)) {
1.23      djm       128:                        if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
                    129:                                if (check_crc(c, buf, len))
1.5       markus    130:                                        return (DEATTACK_DETECTED);
                    131:                                else
                    132:                                        break;
                    133:                        }
                    134:                }
                    135:                h[i] = j;
                    136:        }
                    137:        return (DEATTACK_OK);
1.1       dugsong   138: }