@@ -257,7 +257,7 @@ class OpenVPNClientExport extends Model {
257257 return openvpn_client_export_config (
258258 srvid: $ this ->server ->value ,
259259 usrid: $ this ->username ->value ? $ this ->username ->get_related_model ()->id : null ,
260- crtid: $ this ->certref -> value ? $ this -> certref -> get_related_model ()-> id : null ,
260+ crtid: $ this ->__get_crtid_from_certref () ,
261261 useaddr: $ this ->useaddr_hostname ->value ?? $ this ->useaddr ->value ,
262262 verifyservercn: $ this ->verifyservercn ->value ,
263263 blockoutsidedns: $ this ->blockoutsidedns ->value ,
@@ -291,7 +291,7 @@ class OpenVPNClientExport extends Model {
291291 return openvpn_client_export_installer (
292292 srvid: $ this ->server ->value ,
293293 usrid: $ this ->username ->value ? $ this ->username ->get_related_model ()->id : null ,
294- crtid: $ this ->certref -> value ? $ this -> certref -> get_related_model ()-> id : null ,
294+ crtid: $ this ->__get_crtid_from_certref () ,
295295 useaddr: $ this ->useaddr_hostnam ->value ?? $ this ->useaddr ->value ,
296296 verifyservercn: $ this ->verifyservercn ->value ,
297297 blockoutsidedns: $ this ->blockoutsidedns ->value ,
@@ -319,7 +319,7 @@ class OpenVPNClientExport extends Model {
319319 return viscosity_openvpn_client_config_exporter (
320320 srvid: $ this ->server ->value ,
321321 usrid: $ this ->username ->value ? $ this ->username ->get_related_model ()->id : null ,
322- crtid: $ this ->certref -> value ? $ this -> certref -> get_related_model ()-> id : null ,
322+ crtid: $ this ->__get_crtid_from_certref () ,
323323 useaddr: $ this ->useaddr_hostname ->value ?? $ this ->useaddr ->value ,
324324 verifyservercn: $ this ->verifyservercn ->value ,
325325 blockoutsidedns: $ this ->blockoutsidedns ->value ,
@@ -336,6 +336,42 @@ class OpenVPNClientExport extends Model {
336336 );
337337 }
338338
339+ /**
340+ * Obtains the crtid value pfSense expects for a given certref given the current OpenVPN server and username.
341+ * This is necessary because pfSense's openvpn_client_export_validate_config function sometimes expects
342+ * crtid to be the index of the 'cert' config path, and sometimes expects it to be the index of the
343+ * 'system/user/{$usrid}/cert' config path.
344+ * @returns int|null The crtid value pfSense expects for a given certref, or null if no certref is set.
345+ */
346+ private function __get_crtid_from_certref (): int |null {
347+ # If no certref is set, return null
348+ if (!$ this ->certref ->value ) {
349+ return null ;
350+ }
351+
352+ # Load related models
353+ $ ovpnsrv = $ this ->server ->get_related_model ();
354+ $ user = $ this ->username ->get_related_model ();
355+ $ cert = $ this ->certref ->get_related_model ();
356+
357+ # If a username was provided, the server is using server_tls_user and the local database, pfSense expects
358+ # the crtid to be the index of the 'system/user/{$usrid}/cert' config path not the 'cert' config path.
359+ if (
360+ $ user and
361+ $ ovpnsrv ->mode ->value === 'server_tls_user ' and
362+ $ ovpnsrv ->authmode ->value === ['Local Database ' ]
363+ ) {
364+ foreach ($ user ->cert ->get_config () as $ idx => $ user_cert ) {
365+ if ($ user_cert ['refid ' ] === $ cert ->id ) {
366+ return $ idx ;
367+ }
368+ }
369+ }
370+
371+ # Otherwise, just return the index of the certificate directly
372+ return $ cert ->id ;
373+ }
374+
339375 /**
340376 * Obtains the proxy configuration array expected by pfSense functions.
341377 * @return array the proxy configuration array expected by pfSense functions
0 commit comments