[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.30

1.30    ! djm         1: /* $OpenBSD: deattack.c,v 1.29 2006/08/03 03:34:42 deraadt 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:
1.30    ! djm        33: /*
        !            34:  * CRC attack detection has a worst-case behaviour that is O(N^3) over
        !            35:  * the number of identical blocks in a packet. This behaviour can be
        !            36:  * exploited to create a limited denial of service attack.
        !            37:  *
        !            38:  * However, because we are dealing with encrypted data, identical
        !            39:  * blocks should only occur every 2^35 maximally-sized packets or so.
        !            40:  * Consequently, we can detect this DoS by looking for identical blocks
        !            41:  * in a packet.
        !            42:  *
        !            43:  * The parameter below determines how many identical blocks we will
        !            44:  * accept in a single packet, trading off between attack detection and
        !            45:  * likelihood of terminating a legitimate connection. A value of 32
        !            46:  * corresponds to an average of 2^40 messages before an attack is
        !            47:  * misdetected
        !            48:  */
        !            49: #define MAX_IDENTICAL  32
        !            50:
1.1       dugsong    51: /* SSH Constants */
1.5       markus     52: #define SSH_MAXBLOCKS  (32 * 1024)
                     53: #define SSH_BLOCKSIZE  (8)
1.1       dugsong    54:
                     55: /* Hashing constants */
1.5       markus     56: #define HASH_MINSIZE   (8 * 1024)
                     57: #define HASH_ENTRYSIZE (2)
                     58: #define HASH_FACTOR(x) ((x)*3/2)
                     59: #define HASH_UNUSEDCHAR        (0xff)
                     60: #define HASH_UNUSED    (0xffff)
1.17      deraadt    61: #define HASH_IV                (0xfffe)
1.1       dugsong    62:
1.5       markus     63: #define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
1.1       dugsong    64:
                     65:
                     66: /* Hash function (Input keys are cipher results) */
1.27      djm        67: #define HASH(x)                get_u32(x)
1.1       dugsong    68:
1.13      deraadt    69: #define CMP(a, b)      (memcmp(a, b, SSH_BLOCKSIZE))
1.1       dugsong    70:
1.14      itojun     71: static void
1.5       markus     72: crc_update(u_int32_t *a, u_int32_t b)
1.1       dugsong    73: {
1.5       markus     74:        b ^= *a;
1.22      deraadt    75:        *a = ssh_crc32((u_char *)&b, sizeof(b));
1.1       dugsong    76: }
                     77:
1.5       markus     78: /* detect if a block is used in a particular pattern */
1.14      itojun     79: static int
1.23      djm        80: check_crc(u_char *S, u_char *buf, u_int32_t len)
1.1       dugsong    81: {
1.5       markus     82:        u_int32_t crc;
1.11      markus     83:        u_char *c;
1.1       dugsong    84:
1.5       markus     85:        crc = 0;
                     86:        for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
                     87:                if (!CMP(S, c)) {
                     88:                        crc_update(&crc, 1);
                     89:                        crc_update(&crc, 0);
                     90:                } else {
                     91:                        crc_update(&crc, 0);
                     92:                        crc_update(&crc, 0);
                     93:                }
                     94:        }
                     95:        return (crc == 0);
1.1       dugsong    96: }
                     97:
                     98:
1.5       markus     99: /* Detect a crc32 compensation attack on a packet */
1.1       dugsong   100: int
1.23      djm       101: detect_attack(u_char *buf, u_int32_t len)
1.1       dugsong   102: {
1.5       markus    103:        static u_int16_t *h = (u_int16_t *) NULL;
1.10      markus    104:        static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
1.15      mpech     105:        u_int32_t i, j;
1.30    ! djm       106:        u_int32_t l, same;
1.15      mpech     107:        u_char *c;
1.11      markus    108:        u_char *d;
1.5       markus    109:
                    110:        if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
                    111:            len % SSH_BLOCKSIZE != 0) {
                    112:                fatal("detect_attack: bad length %d", len);
                    113:        }
                    114:        for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
                    115:                ;
1.1       dugsong   116:
1.5       markus    117:        if (h == NULL) {
                    118:                debug("Installing crc compensation attack detector.");
1.24      djm       119:                h = (u_int16_t *) xcalloc(l, HASH_ENTRYSIZE);
1.5       markus    120:                n = l;
                    121:        } else {
                    122:                if (l > n) {
1.25      djm       123:                        h = (u_int16_t *)xrealloc(h, l, HASH_ENTRYSIZE);
1.5       markus    124:                        n = l;
                    125:                }
                    126:        }
                    127:
                    128:        if (len <= HASH_MINBLOCKS) {
                    129:                for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
                    130:                        for (d = buf; d < c; d += SSH_BLOCKSIZE) {
                    131:                                if (!CMP(c, d)) {
1.23      djm       132:                                        if ((check_crc(c, buf, len)))
1.5       markus    133:                                                return (DEATTACK_DETECTED);
                    134:                                        else
                    135:                                                break;
                    136:                                }
                    137:                        }
                    138:                }
                    139:                return (DEATTACK_OK);
                    140:        }
                    141:        memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
                    142:
1.30    ! djm       143:        for (c = buf, same = j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
1.5       markus    144:                for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
1.17      deraadt   145:                    i = (i + 1) & (n - 1)) {
1.23      djm       146:                        if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
1.30    ! djm       147:                                if (++same > MAX_IDENTICAL)
        !           148:                                        return (DEATTACK_DOS_DETECTED);
1.23      djm       149:                                if (check_crc(c, buf, len))
1.5       markus    150:                                        return (DEATTACK_DETECTED);
                    151:                                else
                    152:                                        break;
                    153:                        }
                    154:                }
                    155:                h[i] = j;
                    156:        }
                    157:        return (DEATTACK_OK);
1.1       dugsong   158: }