From d43ba60c91cb323ca921049b7d43b1908c318454 Mon Sep 17 00:00:00 2001
From: "djm@openbsd.org" <djm@openbsd.org>
Date: Mon, 6 Jul 2026 07:44:48 +0000
Subject: upstream: Fix cases in GSSAPI and keyboard-interactive
 authentication where the minimum per-attempt delay was not being enforced.

Reported by Orange Cyberdefense Vulnerability Team

OpenBSD-Commit-ID: c40bd35cc2428fcaccad7a141703c28baa6da01e
Conflict:Adapt context (GSSAPI patches: PRIVSEP, use_privsep guard, indent)
Reference:https://anongit.mindrot.org/openssh.git/commit/?id=c40bd35cc2428fcaccad7a141703c28baa6da01e
---
--- a/auth.h	2026-08-14 11:12:29.675470110 +0800
+++ b/auth.h	2026-08-14 11:12:29.791470967 +0800
@@ -176,6 +176,7 @@
 void	auth_maxtries_exceeded(struct ssh *) __attribute__((noreturn));
 void	userauth_finish(struct ssh *, int, const char *, const char *);
 int	auth_root_allowed(struct ssh *, const char *);
+void	auth_failure_delay(Authctxt *, double);
 
 char	*auth2_read_banner(void);
 int	 auth2_methods_valid(const char *, int);
--- a/auth2-chall.c	2026-08-14 11:12:29.891471706 +0800
+++ b/auth2-chall.c	2026-08-14 11:12:29.991472445 +0800
@@ -296,6 +296,7 @@
 	u_int i, nresp;
 	const char *devicename = NULL;
 	char **response = NULL;
+	double tstart = monotime_double();
 
 	if (authctxt == NULL)
 		fatal_f("no authctxt");
@@ -354,6 +355,9 @@
 			auth2_challenge_start(ssh);
 		}
 	}
+
+	if (!authenticated)
+		auth_failure_delay(authctxt, tstart);
 	userauth_finish(ssh, authenticated, "keyboard-interactive",
 	    devicename);
 	return 0;
--- a/auth2-gss.c	2026-08-14 11:12:30.091473184 +0800
+++ b/auth2-gss.c	2026-08-14 11:12:30.199473982 +0800
@@ -287,6 +287,7 @@
 {
 	Authctxt *authctxt = ssh->authctxt;
 	int r, authenticated;
+	double tstart = monotime_double();
 	const char *displayname;
 
 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
@@ -307,6 +308,9 @@
 	    (displayname = ssh_gssapi_displayname()) != NULL)
 		auth2_record_info(authctxt, "%s", displayname);
 
+
+	if (!authenticated)
+		auth_failure_delay(authctxt, tstart);
 	authctxt->postponed = 0;
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
@@ -328,6 +332,7 @@
 	const char *displayname;
 	u_char *p;
 	size_t len;
+	double tstart = monotime_double();
 
 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
 		fatal("No authentication or GSSAPI context");
@@ -368,6 +373,9 @@
 	    (displayname = ssh_gssapi_displayname()) != NULL)
 		auth2_record_info(authctxt, "%s", displayname);
 
+	if (!authenticated)
+		auth_failure_delay(authctxt, tstart);
+
 	authctxt->postponed = 0;
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
--- a/auth2.c	2026-08-14 11:12:30.307474780 +0800
+++ b/auth2.c	2026-08-14 11:12:30.415475578 +0800
@@ -267,6 +267,12 @@
 	nanosleep(&ts, NULL);
 }
 
+void
+auth_failure_delay(Authctxt *authctxt, double tstart)
+{
+	ensure_minimum_time_since(tstart, user_specific_delay(authctxt->user));
+}
+
 static int
 input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
 {
@@ -365,8 +371,7 @@
 		authenticated =	m->userauth(ssh, method);
 	}
 	if (!authctxt->authenticated && strcmp(method, "none") != 0)
-		ensure_minimum_time_since(tstart,
-		    user_specific_delay(authctxt->user));
+		auth_failure_delay(authctxt, tstart);
 	userauth_finish(ssh, authenticated, method, NULL);
 	r = 0;
  out: