summaryrefslogtreecommitdiffhomepage
path: root/svr-auth.c
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2018-11-05 23:36:34 +0800
committerMatt Johnston <matt@ucc.asn.au>2018-11-05 23:36:34 +0800
commit02ffdd09dc1941f7a924cde8db288fcd64987f59 (patch)
tree2f8bfd41d17f2f291bb0f65cff0cbbd00ef3b38e /svr-auth.c
parent6f6ef4834c792f7ccf2409080a6adaf44b8f0d51 (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.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/svr-auth.c b/svr-auth.c
index 10e51b3..f952b0b 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -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++;
}