diff options
author | Matt Johnston <matt@ucc.asn.au> | 2018-11-05 23:36:34 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2018-11-05 23:36:34 +0800 |
commit | 02ffdd09dc1941f7a924cde8db288fcd64987f59 (patch) | |
tree | 2f8bfd41d17f2f291bb0f65cff0cbbd00ef3b38e /svr-auth.c | |
parent | 6f6ef4834c792f7ccf2409080a6adaf44b8f0d51 (diff) |
- Add adaptive authentication failure delay
- Rework monotonic_now/gettime_wrapper and use clock_gettime on more platforms
Diffstat (limited to 'svr-auth.c')
-rw-r--r-- | svr-auth.c | 45 |
1 files changed, 40 insertions, 5 deletions
@@ -79,6 +79,9 @@ void 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 */ if (ses.authstate.authdone == 1) { TRACE(("leave recv_msg_userauth_request: authdone already")) @@ -382,16 +385,48 @@ void send_msg_userauth_failure(int partial, int incrfail) { encrypt_packet(); if (incrfail) { - unsigned int delay; - genrandom((unsigned char*)&delay, sizeof(delay)); - /* We delay for 300ms +- 50ms */ - delay = 250000 + (delay % 100000); + /* The SSH_MSG_AUTH_FAILURE response is delayed to attempt to + avoid user enumeration and slow brute force attempts. + The delay is adjusted by the time already spent in processing + 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 (!fuzz.fuzzing) #endif { - usleep(delay); + while (nanosleep(&delay, &delay) == -1 && errno == EINTR) { /* Go back to sleep */ } } + ses.authstate.failcount++; } |