mirror of
git://anongit.mindrot.org/openssh.git
synced 2024-12-26 11:52:06 +00:00
d783435315
[OVERVIEW atomicio.c atomicio.h auth-bsdauth.c auth-chall.c auth-krb5.c] [auth-options.c auth-options.h auth-passwd.c auth-rh-rsa.c auth-rhosts.c] [auth-rsa.c auth-skey.c auth.c auth.h auth1.c auth2-chall.c auth2-gss.c] [auth2-hostbased.c auth2-kbdint.c auth2-none.c auth2-passwd.c ] [auth2-pubkey.c auth2.c authfd.c authfd.h authfile.c bufaux.c bufbn.c] [buffer.c buffer.h canohost.c channels.c channels.h cipher-3des1.c] [cipher-bf1.c cipher-ctr.c cipher.c cleanup.c clientloop.c compat.c] [compress.c deattack.c dh.c dispatch.c dns.c dns.h fatal.c groupaccess.c] [groupaccess.h gss-genr.c gss-serv-krb5.c gss-serv.c hostfile.c kex.c] [kex.h kexdh.c kexdhc.c kexdhs.c kexgex.c kexgexc.c kexgexs.c key.c] [key.h log.c log.h mac.c match.c md-sha256.c misc.c misc.h moduli.c] [monitor.c monitor_fdpass.c monitor_mm.c monitor_mm.h monitor_wrap.c] [monitor_wrap.h msg.c nchan.c packet.c progressmeter.c readconf.c] [readconf.h readpass.c rsa.c scard.c scard.h scp.c servconf.c servconf.h] [serverloop.c session.c session.h sftp-client.c sftp-common.c] [sftp-common.h sftp-glob.c sftp-server.c sftp.c ssh-add.c ssh-agent.c] [ssh-dss.c ssh-gss.h ssh-keygen.c ssh-keyscan.c ssh-keysign.c ssh-rsa.c] [ssh.c ssh.h sshconnect.c sshconnect.h sshconnect1.c sshconnect2.c] [sshd.c sshlogin.c sshlogin.h sshpty.c sshpty.h sshtty.c ttymodes.c] [uidswap.c uidswap.h uuencode.c uuencode.h xmalloc.c xmalloc.h] [loginrec.c loginrec.h openbsd-compat/port-aix.c openbsd-compat/port-tun.h] almost entirely get rid of the culture of ".h files that include .h files" ok djm, sort of ok stevesk makes the pain stop in one easy step NB. portable commit contains everything *except* removing includes.h, as that will take a fair bit more work as we move headers that are required for portability workarounds to defines.h. (also, this step wasn't "easy")
141 lines
3.1 KiB
C
141 lines
3.1 KiB
C
/* $OpenBSD: deattack.c,v 1.29 2006/08/03 03:34:42 deraadt Exp $ */
|
|
/*
|
|
* Cryptographic attack detector for ssh - source code
|
|
*
|
|
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
|
*
|
|
* All rights reserved. Redistribution and use in source and binary
|
|
* forms, with or without modification, are permitted provided that
|
|
* this copyright notice is retained.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
|
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
|
* SOFTWARE.
|
|
*
|
|
* Ariel Futoransky <futo@core-sdi.com>
|
|
* <http://www.core-sdi.com>
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "xmalloc.h"
|
|
#include "deattack.h"
|
|
#include "log.h"
|
|
#include "crc32.h"
|
|
#include "misc.h"
|
|
|
|
/* SSH Constants */
|
|
#define SSH_MAXBLOCKS (32 * 1024)
|
|
#define SSH_BLOCKSIZE (8)
|
|
|
|
/* Hashing constants */
|
|
#define HASH_MINSIZE (8 * 1024)
|
|
#define HASH_ENTRYSIZE (2)
|
|
#define HASH_FACTOR(x) ((x)*3/2)
|
|
#define HASH_UNUSEDCHAR (0xff)
|
|
#define HASH_UNUSED (0xffff)
|
|
#define HASH_IV (0xfffe)
|
|
|
|
#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
|
|
|
|
|
|
/* Hash function (Input keys are cipher results) */
|
|
#define HASH(x) get_u32(x)
|
|
|
|
#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
|
|
|
|
static void
|
|
crc_update(u_int32_t *a, u_int32_t b)
|
|
{
|
|
b ^= *a;
|
|
*a = ssh_crc32((u_char *)&b, sizeof(b));
|
|
}
|
|
|
|
/* detect if a block is used in a particular pattern */
|
|
static int
|
|
check_crc(u_char *S, u_char *buf, u_int32_t len)
|
|
{
|
|
u_int32_t crc;
|
|
u_char *c;
|
|
|
|
crc = 0;
|
|
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
|
if (!CMP(S, c)) {
|
|
crc_update(&crc, 1);
|
|
crc_update(&crc, 0);
|
|
} else {
|
|
crc_update(&crc, 0);
|
|
crc_update(&crc, 0);
|
|
}
|
|
}
|
|
return (crc == 0);
|
|
}
|
|
|
|
|
|
/* Detect a crc32 compensation attack on a packet */
|
|
int
|
|
detect_attack(u_char *buf, u_int32_t len)
|
|
{
|
|
static u_int16_t *h = (u_int16_t *) NULL;
|
|
static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
|
u_int32_t i, j;
|
|
u_int32_t l;
|
|
u_char *c;
|
|
u_char *d;
|
|
|
|
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
|
len % SSH_BLOCKSIZE != 0) {
|
|
fatal("detect_attack: bad length %d", len);
|
|
}
|
|
for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
|
;
|
|
|
|
if (h == NULL) {
|
|
debug("Installing crc compensation attack detector.");
|
|
h = (u_int16_t *) xcalloc(l, HASH_ENTRYSIZE);
|
|
n = l;
|
|
} else {
|
|
if (l > n) {
|
|
h = (u_int16_t *)xrealloc(h, l, HASH_ENTRYSIZE);
|
|
n = l;
|
|
}
|
|
}
|
|
|
|
if (len <= HASH_MINBLOCKS) {
|
|
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
|
for (d = buf; d < c; d += SSH_BLOCKSIZE) {
|
|
if (!CMP(c, d)) {
|
|
if ((check_crc(c, buf, len)))
|
|
return (DEATTACK_DETECTED);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return (DEATTACK_OK);
|
|
}
|
|
memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
|
|
|
|
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 (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
|
|
if (check_crc(c, buf, len))
|
|
return (DEATTACK_DETECTED);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
h[i] = j;
|
|
}
|
|
return (DEATTACK_OK);
|
|
}
|