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: }