mirror of
https://github.com/clearml/dropbear
synced 2025-04-21 14:44:56 +00:00
- Add adaptive authentication failure delay
- Rework monotonic_now/gettime_wrapper and use clock_gettime on more platforms
This commit is contained in:
parent
6f6ef4834c
commit
02ffdd09dc
3
auth.h
3
auth.h
@ -108,11 +108,14 @@ struct AuthState {
|
|||||||
unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
|
unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||||
client and server (though has differing
|
client and server (though has differing
|
||||||
meanings). */
|
meanings). */
|
||||||
|
|
||||||
unsigned int perm_warn; /* Server only, set if bad permissions on
|
unsigned int perm_warn; /* Server only, set if bad permissions on
|
||||||
~/.ssh/authorized_keys have already been
|
~/.ssh/authorized_keys have already been
|
||||||
logged. */
|
logged. */
|
||||||
unsigned int checkusername_failed; /* Server only, set if checkusername
|
unsigned int checkusername_failed; /* Server only, set if checkusername
|
||||||
has already failed */
|
has already failed */
|
||||||
|
struct timespec auth_starttime; /* Server only, time of receiving current
|
||||||
|
SSH_MSG_USERAUTH_REQUEST */
|
||||||
|
|
||||||
/* These are only used for the server */
|
/* These are only used for the server */
|
||||||
uid_t pw_uid;
|
uid_t pw_uid;
|
||||||
|
@ -497,6 +497,12 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
|||||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||||
|
|
||||||
|
# POSIX monotonic time
|
||||||
|
OLDCFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199309L"
|
||||||
|
AC_CHECK_FUNCS(clock_gettime)
|
||||||
|
CFLAGS="$OLDCFLAGS"
|
||||||
|
|
||||||
# OS X monotonic time
|
# OS X monotonic time
|
||||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||||
AC_CHECK_FUNCS(mach_absolute_time)
|
AC_CHECK_FUNCS(mach_absolute_time)
|
||||||
|
84
dbutil.c
84
dbutil.c
@ -605,71 +605,67 @@ int constant_time_memcmp(const void* a, const void *b, size_t n)
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
/* higher-resolution monotonic timestamp, falls back to gettimeofday */
|
||||||
/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
|
void gettime_wrapper(struct timespec *now) {
|
||||||
reach userspace include headers */
|
struct timeval tv;
|
||||||
#ifndef CLOCK_MONOTONIC_COARSE
|
|
||||||
#define CLOCK_MONOTONIC_COARSE 6
|
|
||||||
#endif
|
|
||||||
/* Some old toolchains know SYS_clock_gettime but not CLOCK_MONOTONIC */
|
|
||||||
#ifndef CLOCK_MONOTONIC
|
|
||||||
#define CLOCK_MONOTONIC 1
|
|
||||||
#endif
|
|
||||||
static clockid_t get_linux_clock_source() {
|
|
||||||
struct timespec ts;
|
|
||||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
|
|
||||||
return CLOCK_MONOTONIC_COARSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
|
|
||||||
return CLOCK_MONOTONIC;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
time_t monotonic_now() {
|
|
||||||
#if DROPBEAR_FUZZ
|
#if DROPBEAR_FUZZ
|
||||||
if (fuzz.fuzzing) {
|
if (fuzz.fuzzing) {
|
||||||
/* time stands still when fuzzing */
|
/* time stands still when fuzzing */
|
||||||
return 5;
|
now->tv_sec = 5;
|
||||||
|
now->tv_nsec = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||||
|
/* POSIX monotonic clock. Newer Linux, BSD, MacOSX >10.12 */
|
||||||
|
if (clock_gettime(CLOCK_MONOTONIC, now) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||||
{
|
{
|
||||||
static clockid_t clock_source = -2;
|
/* Old linux toolchain - kernel might support it but not the build headers */
|
||||||
|
/* Also glibc <2.17 requires -lrt which we neglect to add */
|
||||||
if (clock_source == -2) {
|
static int linux_monotonic_failed = 0;
|
||||||
/* First run, find out which one works.
|
if (!linux_monotonic_failed) {
|
||||||
-1 will fall back to time() */
|
/* CLOCK_MONOTONIC isn't in some headers */
|
||||||
clock_source = get_linux_clock_source();
|
int clock_source_monotonic = 1;
|
||||||
}
|
if (syscall(SYS_clock_gettime, clock_source_monotonic, now) == 0) {
|
||||||
|
return;
|
||||||
if (clock_source >= 0) {
|
} else {
|
||||||
struct timespec ts;
|
/* Don't try again */
|
||||||
if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
|
linux_monotonic_failed = 1;
|
||||||
/* Intermittent clock failures should not happen */
|
|
||||||
dropbear_exit("Clock broke");
|
|
||||||
}
|
}
|
||||||
return ts.tv_sec;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* linux clock_gettime */
|
#endif /* linux fallback clock_gettime */
|
||||||
|
|
||||||
#if defined(HAVE_MACH_ABSOLUTE_TIME)
|
#if defined(HAVE_MACH_ABSOLUTE_TIME)
|
||||||
{
|
{
|
||||||
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
/* OS X pre 10.12, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||||
static mach_timebase_info_data_t timebase_info;
|
static mach_timebase_info_data_t timebase_info;
|
||||||
|
uint64_t scaled_time;
|
||||||
if (timebase_info.denom == 0) {
|
if (timebase_info.denom == 0) {
|
||||||
mach_timebase_info(&timebase_info);
|
mach_timebase_info(&timebase_info);
|
||||||
}
|
}
|
||||||
return mach_absolute_time() * timebase_info.numer / timebase_info.denom
|
scaled_time = mach_absolute_time() * timebase_info.numer / timebase_info.denom;
|
||||||
/ 1e9;
|
now->tv_sec = scaled_time / 1000000000;
|
||||||
|
now->tv_nsec = scaled_time % 1000000000;
|
||||||
}
|
}
|
||||||
#endif /* osx mach_absolute_time */
|
#endif /* osx mach_absolute_time */
|
||||||
|
|
||||||
/* Fallback for everything else - this will sometimes go backwards */
|
/* Fallback for everything else - this will sometimes go backwards */
|
||||||
return time(NULL);
|
gettimeofday(&tv, NULL);
|
||||||
|
now->tv_sec = tv.tv_sec;
|
||||||
|
now->tv_nsec = 1000*tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* second-resolution monotonic timestamp */
|
||||||
|
time_t monotonic_now() {
|
||||||
|
struct timespec ts;
|
||||||
|
gettime_wrapper(&ts);
|
||||||
|
return ts.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fsync_parent_dir(const char* fn) {
|
void fsync_parent_dir(const char* fn) {
|
||||||
|
2
dbutil.h
2
dbutil.h
@ -83,6 +83,8 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
|
|||||||
/* Returns a time in seconds that doesn't go backwards - does not correspond to
|
/* Returns a time in seconds that doesn't go backwards - does not correspond to
|
||||||
a real-world clock */
|
a real-world clock */
|
||||||
time_t monotonic_now(void);
|
time_t monotonic_now(void);
|
||||||
|
/* Higher resolution clock_gettime(CLOCK_MONOTONIC) wrapper */
|
||||||
|
void gettime_wrapper(struct timespec *now);
|
||||||
|
|
||||||
char * expand_homedir_path(const char *inpath);
|
char * expand_homedir_path(const char *inpath);
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@
|
|||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
|
/* For clock_gettime */
|
||||||
|
#define _POSIX_C_SOURCE 199309L
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/param.h> /* required for BSD4_4 define */
|
#include <sys/param.h> /* required for BSD4_4 define */
|
||||||
|
45
svr-auth.c
45
svr-auth.c
@ -79,6 +79,9 @@ void recv_msg_userauth_request() {
|
|||||||
|
|
||||||
TRACE(("enter recv_msg_userauth_request"))
|
TRACE(("enter recv_msg_userauth_request"))
|
||||||
|
|
||||||
|
/* for compensating failure delay */
|
||||||
|
gettime_wrapper(&ses.authstate.auth_starttime);
|
||||||
|
|
||||||
/* ignore packets if auth is already done */
|
/* ignore packets if auth is already done */
|
||||||
if (ses.authstate.authdone == 1) {
|
if (ses.authstate.authdone == 1) {
|
||||||
TRACE(("leave recv_msg_userauth_request: authdone already"))
|
TRACE(("leave recv_msg_userauth_request: authdone already"))
|
||||||
@ -382,16 +385,48 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
|||||||
encrypt_packet();
|
encrypt_packet();
|
||||||
|
|
||||||
if (incrfail) {
|
if (incrfail) {
|
||||||
unsigned int delay;
|
/* The SSH_MSG_AUTH_FAILURE response is delayed to attempt to
|
||||||
genrandom((unsigned char*)&delay, sizeof(delay));
|
avoid user enumeration and slow brute force attempts.
|
||||||
/* We delay for 300ms +- 50ms */
|
The delay is adjusted by the time already spent in processing
|
||||||
delay = 250000 + (delay % 100000);
|
authentication (ses.authstate.auth_starttime timestamp). */
|
||||||
|
|
||||||
|
/* Desired total delay 300ms +-50ms (in nanoseconds).
|
||||||
|
Beware of integer overflow if increasing these values */
|
||||||
|
const unsigned int mindelay = 250000000;
|
||||||
|
const unsigned int vardelay = 100000000;
|
||||||
|
unsigned int rand_delay;
|
||||||
|
struct timespec delay;
|
||||||
|
|
||||||
|
gettime_wrapper(&delay);
|
||||||
|
delay.tv_sec -= ses.authstate.auth_starttime.tv_sec;
|
||||||
|
delay.tv_nsec -= ses.authstate.auth_starttime.tv_nsec;
|
||||||
|
|
||||||
|
/* carry */
|
||||||
|
if (delay.tv_nsec < 0) {
|
||||||
|
delay.tv_nsec += 1000000000;
|
||||||
|
delay.tv_sec -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
genrandom((unsigned char*)&rand_delay, sizeof(rand_delay));
|
||||||
|
rand_delay = mindelay + (rand_delay % vardelay);
|
||||||
|
|
||||||
|
if (delay.tv_sec == 0 && delay.tv_nsec <= mindelay) {
|
||||||
|
/* Compensate for elapsed time */
|
||||||
|
delay.tv_nsec = rand_delay - delay.tv_nsec;
|
||||||
|
} else {
|
||||||
|
/* No time left or time went backwards, just delay anyway */
|
||||||
|
delay.tv_sec = 0;
|
||||||
|
delay.tv_nsec = rand_delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if DROPBEAR_FUZZ
|
#if DROPBEAR_FUZZ
|
||||||
if (!fuzz.fuzzing)
|
if (!fuzz.fuzzing)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
usleep(delay);
|
while (nanosleep(&delay, &delay) == -1 && errno == EINTR) { /* Go back to sleep */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
ses.authstate.failcount++;
|
ses.authstate.failcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user