From cc16ba7b33d09f3fc4e1b6f673a9ad4d89b669ff Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Wed, 12 Feb 2025 21:12:14 +0100 Subject: [PATCH] VPN: OpenVPN - Support "password first" for static-challenges, closes https://github.com/opnsense/core/pull/8058 --- .../mvc/app/library/OPNsense/Auth/TOTP.php | 8 +++++ .../scripts/openvpn/user_pass_verify.php | 32 ++++++++++++------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/opnsense/mvc/app/library/OPNsense/Auth/TOTP.php b/src/opnsense/mvc/app/library/OPNsense/Auth/TOTP.php index 6a42b3aa9..d322f1fa1 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Auth/TOTP.php +++ b/src/opnsense/mvc/app/library/OPNsense/Auth/TOTP.php @@ -134,6 +134,14 @@ trait TOTP return false; } + /** + * @return bool token after password + */ + public function isPasswordFirst() + { + return $this->passwordFirst; + } + /** * authenticate user against otp key stored in local database * @param string $username username to authenticate diff --git a/src/opnsense/scripts/openvpn/user_pass_verify.php b/src/opnsense/scripts/openvpn/user_pass_verify.php index dfd731401..1d25fd1fb 100755 --- a/src/opnsense/scripts/openvpn/user_pass_verify.php +++ b/src/opnsense/scripts/openvpn/user_pass_verify.php @@ -80,18 +80,7 @@ function do_auth($common_name, $serverid, $method, $auth_file) if (empty($username) || empty($password)) { return "username or password missing ({$method} - {$auth_file})"; } - if (strpos($password, 'SCRV1:') === 0) { - // static-challenge https://github.com/OpenVPN/openvpn/blob/v2.4.7/doc/management-notes.txt#L1146 - // validate and concat password into our default pin+password - $tmp = explode(':', $password); - if (count($tmp) == 3) { - $pass = base64_decode($tmp[1]); - $pin = base64_decode($tmp[2]); - if ($pass !== false && $pin !== false) { - $password = $pin . $pass; - } - } - } + $a_server = $serverid !== null ? (new OPNsense\OpenVPN\OpenVPN())->getInstanceById($serverid, 'server') : null; if ($a_server == null) { return "OpenVPN '$serverid' was not found. Denying authentication for user {$username}"; @@ -121,6 +110,25 @@ function do_auth($common_name, $serverid, $method, $auth_file) foreach (explode(',', $a_server['authmode']) as $authName) { $authenticator = $authFactory->get($authName); if ($authenticator) { + if (strpos($password, 'SCRV1:') === 0) { + // static-challenge https://github.com/OpenVPN/openvpn/blob/v2.4.7/doc/management-notes.txt#L1146 + // validate and concat password into our default pin+password + $tmp = explode(':', $password); + if (count($tmp) == 3) { + $pass = base64_decode($tmp[1]); + $pin = base64_decode($tmp[2]); + if ($pass !== false && $pin !== false) { + if (isset(class_uses($authenticator)[OPNsense\Auth\TOTP::class]) && + $authenticator->isPasswordFirst() + ) { + $password = $pass . $pin; + } else { + $password = $pin . $pass; + } + } + } + } + if ($authenticator->authenticate($username, $password)) { // fetch or create client specific override $common_name = empty($a_server['cso_login_matching']) ? $common_name : $username;