10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * Cryptographic attack detector for ssh - source code
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
50Sstevel@tonic-gate *
60Sstevel@tonic-gate * All rights reserved. Redistribution and use in source and binary
70Sstevel@tonic-gate * forms, with or without modification, are permitted provided that
80Sstevel@tonic-gate * this copyright notice is retained.
90Sstevel@tonic-gate *
100Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
110Sstevel@tonic-gate * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
120Sstevel@tonic-gate * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
130Sstevel@tonic-gate * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
140Sstevel@tonic-gate * SOFTWARE.
150Sstevel@tonic-gate *
160Sstevel@tonic-gate * Ariel Futoransky <futo@core-sdi.com>
170Sstevel@tonic-gate * <http://www.core-sdi.com>
180Sstevel@tonic-gate */
190Sstevel@tonic-gate
200Sstevel@tonic-gate #include "includes.h"
210Sstevel@tonic-gate RCSID("$OpenBSD: deattack.c,v 1.18 2002/03/04 17:27:39 stevesk Exp $");
220Sstevel@tonic-gate
230Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include "deattack.h"
260Sstevel@tonic-gate #include "log.h"
270Sstevel@tonic-gate #include "crc32.h"
280Sstevel@tonic-gate #include "getput.h"
290Sstevel@tonic-gate #include "xmalloc.h"
300Sstevel@tonic-gate #include "deattack.h"
310Sstevel@tonic-gate
32*3102Sjp161948 /*
33*3102Sjp161948 * CRC attack detection has a worst-case behaviour that is O(N^2) over
34*3102Sjp161948 * the number of identical blocks in a packet. This behaviour can be
35*3102Sjp161948 * exploited to create a limited denial of service attack.
36*3102Sjp161948 *
37*3102Sjp161948 * However, because we are dealing with encrypted data, identical
38*3102Sjp161948 * blocks should only occur every 2^35 maximally-sized packets or so.
39*3102Sjp161948 * Consequently, we can detect this DoS by looking for identical blocks
40*3102Sjp161948 * in a packet.
41*3102Sjp161948 *
42*3102Sjp161948 * The parameter below determines how many identical blocks we will
43*3102Sjp161948 * accept in a single packet, trading off between attack detection and
44*3102Sjp161948 * likelihood of terminating a legitimate connection. A value of 32
45*3102Sjp161948 * corresponds to an average of 2^40 messages before an attack is
46*3102Sjp161948 * misdetected
47*3102Sjp161948 */
48*3102Sjp161948 #define MAX_IDENTICAL 32
49*3102Sjp161948
500Sstevel@tonic-gate /* SSH Constants */
510Sstevel@tonic-gate #define SSH_MAXBLOCKS (32 * 1024)
520Sstevel@tonic-gate #define SSH_BLOCKSIZE (8)
530Sstevel@tonic-gate
540Sstevel@tonic-gate /* Hashing constants */
550Sstevel@tonic-gate #define HASH_MINSIZE (8 * 1024)
560Sstevel@tonic-gate #define HASH_ENTRYSIZE (2)
570Sstevel@tonic-gate #define HASH_FACTOR(x) ((x)*3/2)
580Sstevel@tonic-gate #define HASH_UNUSEDCHAR (0xff)
590Sstevel@tonic-gate #define HASH_UNUSED (0xffff)
600Sstevel@tonic-gate #define HASH_IV (0xfffe)
610Sstevel@tonic-gate
620Sstevel@tonic-gate #define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
630Sstevel@tonic-gate
640Sstevel@tonic-gate
650Sstevel@tonic-gate /* Hash function (Input keys are cipher results) */
660Sstevel@tonic-gate #define HASH(x) GET_32BIT(x)
670Sstevel@tonic-gate
680Sstevel@tonic-gate #define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
690Sstevel@tonic-gate
700Sstevel@tonic-gate static void
crc_update(u_int32_t * a,u_int32_t b)710Sstevel@tonic-gate crc_update(u_int32_t *a, u_int32_t b)
720Sstevel@tonic-gate {
730Sstevel@tonic-gate b ^= *a;
740Sstevel@tonic-gate *a = ssh_crc32((u_char *) &b, sizeof(b));
750Sstevel@tonic-gate }
760Sstevel@tonic-gate
770Sstevel@tonic-gate /* detect if a block is used in a particular pattern */
780Sstevel@tonic-gate static int
check_crc(u_char * S,u_char * buf,u_int32_t len,u_char * IV)790Sstevel@tonic-gate check_crc(u_char *S, u_char *buf, u_int32_t len,
800Sstevel@tonic-gate u_char *IV)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate u_int32_t crc;
830Sstevel@tonic-gate u_char *c;
840Sstevel@tonic-gate
850Sstevel@tonic-gate crc = 0;
860Sstevel@tonic-gate if (IV && !CMP(S, IV)) {
870Sstevel@tonic-gate crc_update(&crc, 1);
880Sstevel@tonic-gate crc_update(&crc, 0);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
910Sstevel@tonic-gate if (!CMP(S, c)) {
920Sstevel@tonic-gate crc_update(&crc, 1);
930Sstevel@tonic-gate crc_update(&crc, 0);
940Sstevel@tonic-gate } else {
950Sstevel@tonic-gate crc_update(&crc, 0);
960Sstevel@tonic-gate crc_update(&crc, 0);
970Sstevel@tonic-gate }
980Sstevel@tonic-gate }
990Sstevel@tonic-gate return (crc == 0);
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate /* Detect a crc32 compensation attack on a packet */
1040Sstevel@tonic-gate int
detect_attack(u_char * buf,u_int32_t len,u_char * IV)1050Sstevel@tonic-gate detect_attack(u_char *buf, u_int32_t len, u_char *IV)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate static u_int16_t *h = (u_int16_t *) NULL;
1080Sstevel@tonic-gate static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
1090Sstevel@tonic-gate u_int32_t i, j;
110*3102Sjp161948 u_int32_t l, same;
1110Sstevel@tonic-gate u_char *c;
1120Sstevel@tonic-gate u_char *d;
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
1150Sstevel@tonic-gate len % SSH_BLOCKSIZE != 0) {
1160Sstevel@tonic-gate fatal("detect_attack: bad length %d", len);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
1190Sstevel@tonic-gate ;
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate if (h == NULL) {
1220Sstevel@tonic-gate debug("Installing crc compensation attack detector.");
1230Sstevel@tonic-gate n = l;
1240Sstevel@tonic-gate h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE);
1250Sstevel@tonic-gate } else {
1260Sstevel@tonic-gate if (l > n) {
1270Sstevel@tonic-gate n = l;
1280Sstevel@tonic-gate h = (u_int16_t *) xrealloc(h, n * HASH_ENTRYSIZE);
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate if (len <= HASH_MINBLOCKS) {
1330Sstevel@tonic-gate for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
1340Sstevel@tonic-gate if (IV && (!CMP(c, IV))) {
1350Sstevel@tonic-gate if ((check_crc(c, buf, len, IV)))
1360Sstevel@tonic-gate return (DEATTACK_DETECTED);
1370Sstevel@tonic-gate else
1380Sstevel@tonic-gate break;
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate for (d = buf; d < c; d += SSH_BLOCKSIZE) {
1410Sstevel@tonic-gate if (!CMP(c, d)) {
1420Sstevel@tonic-gate if ((check_crc(c, buf, len, IV)))
1430Sstevel@tonic-gate return (DEATTACK_DETECTED);
1440Sstevel@tonic-gate else
1450Sstevel@tonic-gate break;
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate return (DEATTACK_OK);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate if (IV)
1540Sstevel@tonic-gate h[HASH(IV) & (n - 1)] = HASH_IV;
1550Sstevel@tonic-gate
156*3102Sjp161948 for (c = buf, same = j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
1570Sstevel@tonic-gate for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
1580Sstevel@tonic-gate i = (i + 1) & (n - 1)) {
1590Sstevel@tonic-gate if (h[i] == HASH_IV) {
1600Sstevel@tonic-gate if (!CMP(c, IV)) {
1610Sstevel@tonic-gate if (check_crc(c, buf, len, IV))
1620Sstevel@tonic-gate return (DEATTACK_DETECTED);
1630Sstevel@tonic-gate else
1640Sstevel@tonic-gate break;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
167*3102Sjp161948 if (++same > MAX_IDENTICAL)
168*3102Sjp161948 return (DEATTACK_DOS_DETECTED);
1690Sstevel@tonic-gate if (check_crc(c, buf, len, IV))
1700Sstevel@tonic-gate return (DEATTACK_DETECTED);
1710Sstevel@tonic-gate else
1720Sstevel@tonic-gate break;
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate h[i] = j;
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate return (DEATTACK_OK);
1780Sstevel@tonic-gate }
179