diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 83021a3e6..3d5dc12a4 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -1,353 +1,354 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2018-2023 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
 # published by the Free Software Foundation.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
 from sys import exit
 
 from vyos.base import Warning
 from vyos.config import Config
 from vyos.configdict import dict_merge
 from vyos.pki import wrap_certificate
 from vyos.pki import wrap_private_key
 from vyos.template import render
 from vyos.util import call
 from vyos.util import check_port_availability
 from vyos.util import is_systemd_service_running
 from vyos.util import is_listen_port_bind_service
 from vyos.util import dict_search
 from vyos.xml import defaults
 from vyos import ConfigError
-from crypt import crypt, mksalt, METHOD_SHA512
+from passlib.hash import sha512_crypt
 from time import sleep
 
 from vyos import airbag
 airbag.enable()
 
 cfg_dir        = '/run/ocserv'
 ocserv_conf    = cfg_dir + '/ocserv.conf'
 ocserv_passwd  = cfg_dir + '/ocpasswd'
 ocserv_otp_usr = cfg_dir + '/users.oath'
 radius_cfg     = cfg_dir + '/radiusclient.conf'
 radius_servers = cfg_dir + '/radius_servers'
 
 # Generate hash from user cleartext password
 def get_hash(password):
-    return crypt(password, mksalt(METHOD_SHA512))
+    return sha512_crypt.hash(password)
+
 
 
 def _default_dict_cleanup(origin: dict, default_values: dict) -> dict:
     """
     https://vyos.dev/T2665
     Clear unnecessary key values in merged config by dict_merge function
     :param origin: config
     :type origin: dict
     :param default_values: default values
     :type default_values: dict
     :return: merged dict
     :rtype: dict
     """
     if 'mode' in origin["authentication"] and "local" in \
             origin["authentication"]["mode"]:
         del origin['authentication']['local_users']['username']['otp']
         if not origin["authentication"]["local_users"]["username"]:
             raise ConfigError(
                 'Openconnect authentication mode local requires at least one user')
         default_ocserv_usr_values = \
         default_values['authentication']['local_users']['username']['otp']
         for user, params in origin['authentication']['local_users'][
             'username'].items():
             # Not every configuration requires OTP settings
             if origin['authentication']['local_users']['username'][user].get(
                     'otp'):
                 origin['authentication']['local_users']['username'][user][
                     'otp'] = dict_merge(default_ocserv_usr_values,
                                         origin['authentication'][
                                             'local_users']['username'][user][
                                             'otp'])
 
     if 'mode' in origin["authentication"] and "radius" in \
             origin["authentication"]["mode"]:
         del origin['authentication']['radius']['server']['port']
         if not origin["authentication"]['radius']['server']:
             raise ConfigError(
                 'Openconnect authentication mode radius requires at least one RADIUS server')
         default_values_radius_port = \
         default_values['authentication']['radius']['server']['port']
         for server, params in origin['authentication']['radius'][
             'server'].items():
             if 'port' not in params:
                 params['port'] = default_values_radius_port
 
     if 'mode' in origin["accounting"] and "radius" in \
             origin["accounting"]["mode"]:
         del origin['accounting']['radius']['server']['port']
         if not origin["accounting"]['radius']['server']:
             raise ConfigError(
                 'Openconnect accounting mode radius requires at least one RADIUS server')
         default_values_radius_port = \
             default_values['accounting']['radius']['server']['port']
         for server, params in origin['accounting']['radius'][
             'server'].items():
             if 'port' not in params:
                 params['port'] = default_values_radius_port
     return origin
 
 
 def get_config(config=None):
     if config:
         conf = config
     else:
         conf = Config()
     base = ['vpn', 'openconnect']
     if not conf.exists(base):
         return None
 
     ocserv = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
     # We have gathered the dict representation of the CLI, but there are default
     # options which we need to update into the dictionary retrived.
     default_values = defaults(base)
     ocserv = dict_merge(default_values, ocserv)
     # workaround a "know limitation" - https://vyos.dev/T2665
     ocserv = _default_dict_cleanup(ocserv, default_values)
     if ocserv:
         ocserv['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
                                 get_first_key=True, no_tag_node_value_mangle=True)
 
     return ocserv
 
 def verify(ocserv):
     if ocserv is None:
         return None
     # Check if listen-ports not binded other services
     # It can be only listen by 'ocserv-main'
     for proto, port in ocserv.get('listen_ports').items():
         if check_port_availability(ocserv['listen_address'], int(port), proto) is not True and \
                 not is_listen_port_bind_service(int(port), 'ocserv-main'):
             raise ConfigError(f'"{proto}" port "{port}" is used by another service')
 
     # Check accounting
     if "accounting" in ocserv:
         if "mode" in ocserv["accounting"] and "radius" in ocserv["accounting"]["mode"]:
             if "authentication" not in ocserv or "mode" not in ocserv["authentication"]:
                 raise ConfigError('Accounting depends on OpenConnect authentication configuration')
             elif "radius" not in ocserv["authentication"]["mode"]:
                 raise ConfigError('RADIUS accounting must be used with RADIUS authentication')
 
     # Check authentication
     if "authentication" in ocserv:
         if "mode" in ocserv["authentication"]:
             if "local" in ocserv["authentication"]["mode"]:
                 if "radius" in ocserv["authentication"]["mode"]:
                     raise ConfigError('OpenConnect authentication modes are mutually-exclusive, remove either local or radius from your configuration')
                 if not ocserv["authentication"]["local_users"]:
                     raise ConfigError('openconnect mode local required at least one user')
                 if not ocserv["authentication"]["local_users"]["username"]:
                     raise ConfigError('openconnect mode local required at least one user')
                 else:
                     # For OTP mode: verify that each local user has an OTP key
                     if "otp" in ocserv["authentication"]["mode"]["local"]:
                         users_wo_key = []
                         for user, user_config in ocserv["authentication"]["local_users"]["username"].items():
                             # User has no OTP key defined
                             if dict_search('otp.key', user_config) == None:
                                 users_wo_key.append(user)
                         if users_wo_key:
                             raise ConfigError(f'OTP enabled, but no OTP key is configured for these users:\n{users_wo_key}')
                     # For password (and default) mode: verify that each local user has password
                     if "password" in ocserv["authentication"]["mode"]["local"] or "otp" not in ocserv["authentication"]["mode"]["local"]:
                         users_wo_pswd = []
                         for user in ocserv["authentication"]["local_users"]["username"]:
                             if not "password" in ocserv["authentication"]["local_users"]["username"][user]:
                                 users_wo_pswd.append(user)
                         if users_wo_pswd:
                             raise ConfigError(f'password required for users:\n{users_wo_pswd}')
 
             # Validate that if identity-based-config is configured all child config nodes are set
             if 'identity_based_config' in ocserv["authentication"]:
                 if 'disabled' not in ocserv["authentication"]["identity_based_config"]:
                     Warning("Identity based configuration files is a 3rd party addition. Use at your own risk, this might break the ocserv daemon!")
                     if 'mode' not in ocserv["authentication"]["identity_based_config"]:
                         raise ConfigError('OpenConnect radius identity-based-config enabled but mode not selected')
                     elif 'group' in ocserv["authentication"]["identity_based_config"]["mode"] and "radius" not in ocserv["authentication"]["mode"]:
                         raise ConfigError('OpenConnect config-per-group must be used with radius authentication')
                     if 'directory' not in ocserv["authentication"]["identity_based_config"]:
                         raise ConfigError('OpenConnect identity-based-config enabled but directory not set')
                     if 'default_config' not in ocserv["authentication"]["identity_based_config"]:
                         raise ConfigError('OpenConnect identity-based-config enabled but default-config not set')
         else:
             raise ConfigError('openconnect authentication mode required')
     else:
         raise ConfigError('openconnect authentication credentials required')
 
     # Check ssl
     if 'ssl' not in ocserv:
         raise ConfigError('openconnect ssl required')
 
     if not ocserv['pki'] or 'certificate' not in ocserv['pki']:
         raise ConfigError('PKI not configured')
 
     ssl = ocserv['ssl']
     if 'certificate' not in ssl:
         raise ConfigError('openconnect ssl certificate required')
 
     cert_name = ssl['certificate']
 
     if cert_name not in ocserv['pki']['certificate']:
         raise ConfigError('Invalid openconnect ssl certificate')
 
     cert = ocserv['pki']['certificate'][cert_name]
 
     if 'certificate' not in cert:
         raise ConfigError('Missing certificate in PKI')
 
     if 'private' not in cert or 'key' not in cert['private']:
         raise ConfigError('Missing private key in PKI')
 
     if 'ca_certificate' in ssl:
         if 'ca' not in ocserv['pki']:
             raise ConfigError('PKI not configured')
 
         if ssl['ca_certificate'] not in ocserv['pki']['ca']:
             raise ConfigError('Invalid openconnect ssl CA certificate')
 
     # Check network settings
     if "network_settings" in ocserv:
         if "push_route" in ocserv["network_settings"]:
             # Replace default route
             if "0.0.0.0/0" in ocserv["network_settings"]["push_route"]:
                 ocserv["network_settings"]["push_route"].remove("0.0.0.0/0")
                 ocserv["network_settings"]["push_route"].append("default")
         else:
             ocserv["network_settings"]["push_route"] = ["default"]
     else:
         raise ConfigError('openconnect network settings required')
 
 def generate(ocserv):
     if not ocserv:
         return None
 
     if "radius" in ocserv["authentication"]["mode"]:
         if dict_search(ocserv, 'accounting.mode.radius'):
             # Render radius client configuration
             render(radius_cfg, 'ocserv/radius_conf.j2', ocserv)
             merged_servers = ocserv["accounting"]["radius"]["server"] | ocserv["authentication"]["radius"]["server"]
             # Render radius servers
             # Merge the accounting and authentication servers into a single dictionary
             render(radius_servers, 'ocserv/radius_servers.j2', {'server': merged_servers})
         else:
             # Render radius client configuration
             render(radius_cfg, 'ocserv/radius_conf.j2', ocserv)
             # Render radius servers
             render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"])
     elif "local" in ocserv["authentication"]["mode"]:
         # if mode "OTP", generate OTP users file parameters
         if "otp" in ocserv["authentication"]["mode"]["local"]:
             if "local_users" in ocserv["authentication"]:
                 for user in ocserv["authentication"]["local_users"]["username"]:
                     # OTP token type from CLI parameters:
                     otp_interval = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("interval"))
                     token_type = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("token_type")
                     otp_length = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("otp_length"))
                     if token_type == "hotp-time":
                         otp_type = "HOTP/T" + otp_interval
                     elif token_type == "hotp-event":
                         otp_type = "HOTP/E"
                     else:
                         otp_type = "HOTP/T" + otp_interval
                     ocserv["authentication"]["local_users"]["username"][user]["otp"]["token_tmpl"] = otp_type + "/" + otp_length
         # if there is a password, generate hash
         if "password" in ocserv["authentication"]["mode"]["local"] or not "otp" in ocserv["authentication"]["mode"]["local"]:
             if "local_users" in ocserv["authentication"]:
                 for user in ocserv["authentication"]["local_users"]["username"]:
                     ocserv["authentication"]["local_users"]["username"][user]["hash"] = get_hash(ocserv["authentication"]["local_users"]["username"][user]["password"])
 
         if "password-otp" in ocserv["authentication"]["mode"]["local"]:
             # Render local users ocpasswd
             render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
             # Render local users OTP keys
             render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.j2', ocserv["authentication"]["local_users"])
         elif "password" in ocserv["authentication"]["mode"]["local"]:
             # Render local users ocpasswd
             render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
         elif "otp" in ocserv["authentication"]["mode"]["local"]:
             # Render local users OTP keys
             render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.j2', ocserv["authentication"]["local_users"])
         else:
             # Render local users ocpasswd
             render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
     else:
         if "local_users" in ocserv["authentication"]:
             for user in ocserv["authentication"]["local_users"]["username"]:
                 ocserv["authentication"]["local_users"]["username"][user]["hash"] = get_hash(ocserv["authentication"]["local_users"]["username"][user]["password"])
             # Render local users
             render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
 
     if "ssl" in ocserv:
         cert_file_path = os.path.join(cfg_dir, 'cert.pem')
         cert_key_path = os.path.join(cfg_dir, 'cert.key')
         ca_cert_file_path = os.path.join(cfg_dir, 'ca.pem')
 
         if 'certificate' in ocserv['ssl']:
             cert_name = ocserv['ssl']['certificate']
             pki_cert = ocserv['pki']['certificate'][cert_name]
 
             with open(cert_file_path, 'w') as f:
                 f.write(wrap_certificate(pki_cert['certificate']))
 
             if 'private' in pki_cert and 'key' in pki_cert['private']:
                 with open(cert_key_path, 'w') as f:
                     f.write(wrap_private_key(pki_cert['private']['key']))
 
         if 'ca_certificate' in ocserv['ssl']:
             ca_name = ocserv['ssl']['ca_certificate']
             pki_ca_cert = ocserv['pki']['ca'][ca_name]
 
             with open(ca_cert_file_path, 'w') as f:
                 f.write(wrap_certificate(pki_ca_cert['certificate']))
 
     # Render config
     render(ocserv_conf, 'ocserv/ocserv_config.j2', ocserv)
 
 
 def apply(ocserv):
     if not ocserv:
         call('systemctl stop ocserv.service')
         for file in [ocserv_conf, ocserv_passwd, ocserv_otp_usr]:
             if os.path.exists(file):
                 os.unlink(file)
     else:
         call('systemctl reload-or-restart ocserv.service')
         counter = 0
         while True:
             # exit early when service runs
             if is_systemd_service_running("ocserv.service"):
                 break
             sleep(0.250)
             if counter > 5:
                 raise ConfigError('openconnect failed to start, check the logs for details')
                 break
             counter += 1
 
 
 if __name__ == '__main__':
     try:
         c = get_config()
         verify(c)
         generate(c)
         apply(c)
     except ConfigError as e:
         print(e)
         exit(1)