Copyright (c) <2023> <NTC CONTACT, Minsk, Belarus>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


diff -ruN strongswan-5.8.4/configure.ac strongswancont-5.8.4-svc/configure.ac
--- strongswan-5.8.4/configure.ac	2020-03-29 13:49:52.000000000 +0300
+++ strongswancont-5.8.4-svc/configure.ac	2023-06-15 18:33:50.571474053 +0300
@@ -177,9 +177,9 @@
 ARG_DISBL_SET([sshkey],         [disable SSH key decoding plugin.])
 ARG_DISBL_SET([x509],           [disable X509 certificate implementation plugin.])
 # fetcher/resolver plugins
-ARG_ENABL_SET([curl],           [enable CURL fetcher plugin to fetch files via libcurl. Requires libcurl.])
+ARG_DISBL_SET([curl],           [disable CURL fetcher plugin to fetch files via libcurl. Requires libcurl.])
 ARG_ENABL_SET([files],          [enable simple file:// URI fetcher.])
-ARG_ENABL_SET([ldap],           [enable LDAP fetching plugin to fetch files via libldap. Requires openLDAP.])
+ARG_DISBL_SET([ldap],           [disable LDAP fetching plugin to fetch files via libldap. Requires openLDAP.])
 ARG_ENABL_SET([soup],           [enable soup fetcher plugin to fetch from HTTP via libsoup. Requires libsoup.])
 ARG_ENABL_SET([unbound],        [enable UNBOUND resolver plugin to perform DNS queries via libunbound. Requires libldns and libunbound.])
 ARG_ENABL_SET([winhttp],        [enable WinHTTP based HTTP/HTTPS fetching plugin.])
@@ -189,7 +189,7 @@
 # authentication/credential plugins
 ARG_ENABL_SET([addrblock],      [enables RFC 3779 address block constraint support.])
 ARG_ENABL_SET([acert],          [enable X509 attribute certificate checking plugin.])
-ARG_ENABL_SET([agent],          [enables the ssh-agent signing plugin.])
+ARG_DISBL_SET([agent],          [disable the ssh-agent signing plugin.])
 ARG_DISBL_SET([constraints],    [disable advanced X509 constraint checking plugin.])
 ARG_ENABL_SET([coupling],       [enable IKEv2 plugin to couple peer certificates permanently to authentication.])
 ARG_ENABL_SET([dnscert],        [enable DNSCERT authentication plugin.])
@@ -202,7 +202,7 @@
 ARG_ENABL_SET([eap-simaka-sql], [enable EAP-SIM/AKA backend based on a triplet/quintuplet SQL database.])
 ARG_ENABL_SET([eap-simaka-pseudonym], [enable EAP-SIM/AKA pseudonym storage plugin.])
 ARG_ENABL_SET([eap-simaka-reauth],    [enable EAP-SIM/AKA reauthentication data storage plugin.])
-ARG_ENABL_SET([eap-identity],   [enable EAP module providing EAP-Identity helper.])
+ARG_DISBL_SET([eap-identity],   [disable EAP module providing EAP-Identity helper.])
 ARG_ENABL_SET([eap-md5],        [enable EAP MD5 (CHAP) authentication module.])
 ARG_ENABL_SET([eap-gtc],        [enable EAP GTC authentication module.])
 ARG_ENABL_SET([eap-mschapv2],   [enable EAP MS-CHAPv2 authentication module.])
@@ -228,7 +228,7 @@
 ARG_ENABL_SET([kernel-pfkey],   [enable the PF_KEY kernel interface.])
 ARG_ENABL_SET([kernel-pfroute], [enable the PF_ROUTE kernel interface.])
 ARG_ENABL_SET([kernel-iph],     [enable the Windows IP Helper based networking backend.])
-ARG_ENABL_SET([kernel-libipsec],[enable the libipsec kernel interface.])
+ARG_DISBL_SET([kernel-libipsec],[disable the libipsec kernel interface.])
 ARG_ENABL_SET([kernel-wfp],     [enable the Windows Filtering Platform IPsec backend.])
 ARG_DISBL_SET([socket-default], [disable default socket implementation for charon.])
 ARG_ENABL_SET([socket-dynamic], [enable dynamic socket implementation for charon])
@@ -243,7 +243,7 @@
 ARG_ENABL_SET([android-dns],    [enable Android specific DNS handler.])
 ARG_DISBL_SET([attr],           [disable strongswan.conf based configuration attribute plugin.])
 ARG_ENABL_SET([attr-sql],       [enable SQL based configuration attribute plugin.])
-ARG_ENABL_SET([dhcp],           [enable DHCP based attribute provider plugin.])
+ARG_DISBL_SET([dhcp],           [disable DHCP based attribute provider plugin.])
 ARG_ENABL_SET([osx-attr],       [enable OS X SystemConfiguration attribute handler.])
 ARG_ENABL_SET([p-cscf],         [enable plugin to request P-CSCF server addresses from an ePDG.])
 ARG_DISBL_SET([resolve],        [disable resolve DNS handler plugin.])
@@ -298,7 +298,7 @@
 ARG_ENABL_SET([manager],        [enable web management console (proof of concept).])
 ARG_ENABL_SET([medcli],         [enable mediation client configuration database plugin.])
 ARG_ENABL_SET([medsrv],         [enable mediation server web frontend and daemon plugin.])
-ARG_ENABL_SET([nm],             [enable NetworkManager backend.])
+ARG_DISBL_SET([nm],             [disable NetworkManager backend.])
 ARG_DISBL_SET([pki],            [disable pki certificate utility.])
 ARG_DISBL_SET([scepclient],     [disable SCEP client tool.])
 ARG_DISBL_SET([scripts],        [disable additional utilities (found in directory scripts).])
@@ -330,6 +330,7 @@
 ARG_ENABL_SET([lock-profiler],  [enable lock/mutex profiling code.])
 ARG_ENABL_SET([log-thread-ids], [use thread ID, if available, instead of an incremented value starting from 1, to identify threads.])
 ARG_ENABL_SET([monolithic],     [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.])
+ARG_ENABL_SET([wintun],         [enable wintun TUN driver support.])
 
 # ===================================
 #  option to disable default options
@@ -1477,7 +1478,7 @@
 ADD_PLUGIN([attr],                 [c charon])
 ADD_PLUGIN([attr-sql],             [c charon])
 ADD_PLUGIN([load-tester],          [c charon])
-ADD_PLUGIN([kernel-libipsec],      [c charon cmd])
+ADD_PLUGIN([kernel-libipsec],      [c charon nm cmd])
 ADD_PLUGIN([kernel-wfp],           [c charon])
 ADD_PLUGIN([kernel-iph],           [c charon])
 ADD_PLUGIN([kernel-pfkey],         [c charon starter nm cmd])
@@ -1530,7 +1531,7 @@
 ADD_PLUGIN([tnccs-dynamic],        [t charon])
 ADD_PLUGIN([medsrv],               [c charon])
 ADD_PLUGIN([medcli],               [c charon])
-ADD_PLUGIN([dhcp],                 [c charon])
+ADD_PLUGIN([dhcp],                 [c charon nm cmd])
 ADD_PLUGIN([osx-attr],             [c charon cmd])
 ADD_PLUGIN([p-cscf],               [c charon cmd])
 ADD_PLUGIN([android-dns],          [c charon])
@@ -1786,6 +1787,7 @@
 AM_CONDITIONAL(USE_PERL_CPAN, test x$perl_cpan = xtrue)
 AM_CONDITIONAL(USE_TOX, test "x$TOX" != x)
 AM_CONDITIONAL(USE_PY_TEST, test "x$PY_TEST" != x -a "x$TOX" = x)
+AM_CONDITIONAL(USE_WINTUN, test "x$wintun" != x)
 
 # ========================
 #  set global definitions
@@ -1818,6 +1820,9 @@
 if test x$imc_swima = xtrue -o x$imv_swima = xtrue; then
 	AC_DEFINE([USE_JSON], [], [build code for JSON])
 fi
+if test x$wintun = xtrue; then
+	AC_DEFINE([USE_WINTUN], [], [Build in wintun TUN driver support])
+fi
 
 # ====================================================
 #  options for enabled modules (see conf/Makefile.am)
@@ -1839,6 +1844,7 @@
 AM_COND_IF([USE_PKI], [strongswan_options=${strongswan_options}" pki"])
 AM_COND_IF([USE_SWANCTL], [strongswan_options=${strongswan_options}" swanctl"])
 AM_COND_IF([USE_SYSTEMD], [strongswan_options=${strongswan_options}" charon-systemd"])
+#AM_COND_IF([USE_SVC], [strongswan_options=${strongswan_options}" charon-svc"])
 
 AC_SUBST(strongswan_options)
 
diff -ruN strongswan-5.8.4/src/charon/charon.c strongswancont-5.8.4-svc/src/charon/charon.c
--- strongswan-5.8.4/src/charon/charon.c	2019-08-27 16:26:53.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon/charon.c	2022-07-06 15:47:33.738966000 +0300
@@ -366,6 +366,7 @@
 			{ "debug-tls", required_argument, &group, DBG_TLS },
 			{ "debug-esp", required_argument, &group, DBG_ESP },
 			{ "debug-lib", required_argument, &group, DBG_LIB },
+			{ "debug-cnt", required_argument, &group, DBG_CNT },
 			{ 0,0,0,0 }
 		};
 
@@ -379,7 +380,7 @@
 				status = 0;
 				goto deinit;
 			case 'v':
-				printf("Linux strongSwan %s\n", VERSION);
+				printf("Linux strongSwanCont %s\n", VERSION);
 				status = 0;
 				goto deinit;
 			case 'l':
@@ -410,7 +411,7 @@
 	{
 		memset(&utsname, 0, sizeof(utsname));
 	}
-	DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)",
+	DBG1(DBG_DMN, "Starting IKE charon daemon (STC CONTACT "VERSION", %s %s, %s)",
 		  utsname.sysname, utsname.release, utsname.machine);
 	if (lib->integrity)
 	{
diff -ruN strongswan-5.8.4/src/charon-nm/charon-nm.c strongswancont-5.8.4-svc/src/charon-nm/charon-nm.c
--- strongswan-5.8.4/src/charon-nm/charon-nm.c	2020-03-29 12:01:12.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/charon-nm.c	2022-07-06 15:47:33.746967000 +0300
@@ -200,7 +200,7 @@
 	lib->settings->set_default_str(lib->settings, "charon-nm.port", "0");
 	lib->settings->set_default_str(lib->settings, "charon-nm.port_nat_t", "0");
 
-	DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
+	DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwanCont "VERSION")");
 	if (lib->integrity)
 	{
 		DBG1(DBG_DMN, "integrity tests enabled:");
diff -ruN strongswan-5.8.4/src/charon-nm/Makefile.am strongswancont-5.8.4-svc/src/charon-nm/Makefile.am
--- strongswan-5.8.4/src/charon-nm/Makefile.am	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/Makefile.am	2022-07-06 15:47:33.746967000 +0300
@@ -23,6 +23,6 @@
 	$(top_builddir)/src/libcharon/libcharon.la \
 	-lm $(PTHREADLIB) $(ATOMICLIB) $(DLLIB) ${nm_LIBS}
 
-dbuspolicy_DATA = nm-strongswan-service.conf
+dbuspolicy_DATA = nm-strongswancont-service.conf
 
 EXTRA_DIST = $(dbuspolicy_DATA)
diff -ruN strongswan-5.8.4/src/charon-nm/nm/nm_creds.c strongswancont-5.8.4-svc/src/charon-nm/nm/nm_creds.c
--- strongswan-5.8.4/src/charon-nm/nm/nm_creds.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/nm/nm_creds.c	2022-07-06 15:47:33.746967000 +0300
@@ -41,6 +41,11 @@
 	linked_list_t *certs;
 
 	/**
+	 * List of revocation lists, certificate_t*
+	 */
+	linked_list_t *crls;
+
+	/**
 	 * User name
 	 */
 	identification_t *user;
@@ -77,6 +82,17 @@
 };
 
 /**
+ * Enumerator for revocation lists
+ */
+static enumerator_t *create_crl_enumerator(private_nm_creds_t *this)
+{
+	this->lock->read_lock(this->lock);
+	return enumerator_create_cleaner(this->crls->create_enumerator(this->crls),
+							(void*)this->lock->unlock, this->lock);
+
+}
+
+/**
  * Enumerator for user certificate
  */
 static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this,
@@ -198,6 +214,10 @@
 	{
 		return create_trusted_cert_enumerator(this, key, id);
 	}
+	if (cert == CERT_X509_CRL)
+	{
+		return create_crl_enumerator(this);
+	}
 	return NULL;
 }
 
@@ -389,6 +409,56 @@
 	}
 }
 
+/**
+ * Load a CRL file
+ */
+static void load_crl_file(private_nm_creds_t *this, char *file)
+{
+	certificate_t *cert;
+
+	/* We add the CA constraint, as many CAs miss it */
+	cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
+							  BUILD_FROM_FILE, file, BUILD_END);
+	if (!cert)
+	{
+		DBG1(DBG_CFG, "loading CRL '%s' failed", file);
+	}
+	else
+	{
+		DBG2(DBG_CFG, "loaded CRL '%s'", file);
+		this->crls->insert_last(this->crls, cert);
+	}
+}
+
+METHOD(nm_creds_t, load_crl_dir, void,
+	private_nm_creds_t *this, char *dir)
+{
+	enumerator_t *enumerator;
+	char *rel, *abs;
+	struct stat st;
+
+	enumerator = enumerator_create_directory(dir);
+	if (enumerator)
+	{
+		while (enumerator->enumerate(enumerator, &rel, &abs, &st))
+		{
+			/* skip '.', '..' and hidden files */
+			if (rel[0] != '.')
+			{
+				if (S_ISDIR(st.st_mode))
+				{
+					load_crl_dir(this, abs);
+				}
+				else if (S_ISREG(st.st_mode))
+				{
+					load_crl_file(this, abs);
+				}
+			}
+		}
+		enumerator->destroy(enumerator);
+	}
+}
+
 METHOD(nm_creds_t, set_username_password, void,
 	private_nm_creds_t *this, identification_t *id, char *password)
 {
@@ -440,6 +510,10 @@
 	{
 		cert->destroy(cert);
 	}
+	while (this->crls->remove_last(this->crls, (void**)&cert) == SUCCESS)
+	{
+		cert->destroy(cert);
+	}
 	DESTROY_IF(this->user);
 	free(this->pass);
 	free(this->keypass);
@@ -459,6 +533,7 @@
 {
 	clear(this);
 	this->certs->destroy(this->certs);
+	this->crls->destroy(this->crls);
 	this->lock->destroy(this->lock);
 	free(this);
 }
@@ -481,6 +556,7 @@
 			},
 			.add_certificate = _add_certificate,
 			.load_ca_dir = _load_ca_dir,
+			.load_crl_dir = _load_crl_dir,
 			.set_username_password = _set_username_password,
 			.set_key_password = _set_key_password,
 			.set_pin = _set_pin,
@@ -490,6 +566,7 @@
 		},
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
 		.certs = linked_list_create(),
+		.crls = linked_list_create(),
 	);
 	return &this->public;
 }
diff -ruN strongswan-5.8.4/src/charon-nm/nm/nm_creds.h strongswancont-5.8.4-svc/src/charon-nm/nm/nm_creds.h
--- strongswan-5.8.4/src/charon-nm/nm/nm_creds.h	2018-10-04 00:35:16.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/nm/nm_creds.h	2022-07-06 15:47:33.746967000 +0300
@@ -51,6 +51,13 @@
 	void (*load_ca_dir)(nm_creds_t *this, char *dir);
 
 	/**
+	 * Load CRLs recursively from a directory.
+	 *
+	 * @param dir		directory to CRLs
+	 */
+	void (*load_crl_dir)(nm_creds_t *this, char *dir);
+
+	/**
 	 * Set the username/password for authentication.
 	 *
 	 * @param id		ID of the user
diff -ruN strongswan-5.8.4/src/charon-nm/nm/nm_service.c strongswancont-5.8.4-svc/src/charon-nm/nm/nm_service.c
--- strongswan-5.8.4/src/charon-nm/nm/nm_service.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/nm/nm_service.c	2022-07-06 15:47:33.746967000 +0300
@@ -307,22 +307,12 @@
 	NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
 	bool up)
 {
-	if (this->ike_sa == ike_sa)
+	if (this->ike_sa == ike_sa && up)
 	{
-		if (up)
-		{	/* disable initiate-failure-detection hooks */
-			this->listener.ike_state_change = NULL;
-			this->listener.child_state_change = NULL;
-			signal_ip_config(this->plugin, ike_sa, child_sa);
-		}
-		else
-		{
-			if (ike_sa->has_condition(ike_sa, COND_REAUTHENTICATING))
-			{	/* we ignore this during reauthentication */
-				return TRUE;
-			}
-			signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
-		}
+		/* disable initiate-failure-detection hooks */
+		this->listener.ike_state_change = NULL;
+		this->listener.child_state_change = NULL;
+		signal_ip_config(this->plugin, ike_sa, child_sa);
 	}
 	return TRUE;
 }
@@ -390,10 +380,11 @@
 	identification_t *id = NULL;
 	certificate_t *cert = NULL;
 	auth_cfg_t *auth;
-	const char *str, *method, *cert_source;
+	const char *str, *method, *cert_source,  *userkey_source;
 
 	method = nm_setting_vpn_get_data_item(vpn, "method");
 	cert_source = nm_setting_vpn_get_data_item(vpn, "cert-source") ?: method;
+	userkey_source = nm_setting_vpn_get_data_item(vpn, "userkey-source");
 
 	if (streq(cert_source, "smartcard"))
 	{
@@ -450,19 +441,42 @@
 							"Connecting to SSH agent failed.");
 			}
 		}
+		/* ... or usbbar */
+		if (streq(userkey_source, "usbbar")) 
+		{
+			char *secret;
+			secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
+			private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+							KEY_ANY, BUILD_USBBAR_PWD, secret, BUILD_END);
+			if (!private)
+			{
+				g_set_error(err, NM_VPN_PLUGIN_ERROR,
+							NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+							"Loading private key failed.");
+			}
+		}
 		/* ... or key file */
 		str = nm_setting_vpn_get_data_item(vpn, "userkey");
 		if (!agent && str)
 		{
 			char *secret;
-
 			secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
-			if (secret)
+			if (streq(userkey_source, "bpki"))
 			{
-				priv->creds->set_key_password(priv->creds, secret);
-			}
-			private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+				const char *params = nm_setting_vpn_get_data_item(vpn, "bpki-params");
+				if (params)
+				{
+					char params_with_pwd[2048] = {0};
+					sprintf(params_with_pwd, "%s PWD=\"%s\"", params, secret);
+					private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+									KEY_BIGN, BUILD_BPKI_PARAMS, chunk_from_str(params_with_pwd), BUILD_END);
+				}				
+			}			
+			else
+			{
+				private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
 									KEY_ANY, BUILD_FROM_FILE, str, BUILD_END);
+			}
 			if (!private)
 			{
 				g_set_error(err, NM_VPN_PLUGIN_ERROR,
@@ -497,6 +511,11 @@
 		auth->add(auth, AUTH_RULE_AAA_IDENTITY,
 				  identification_create_from_string("%any"));
 	}
+	else if (streq(method, "eap-bsts"))
+	{
+		auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
+		auth->add(auth, AUTH_RULE_EAP_TYPE, EAP_BSTS);		
+	}
 	else
 	{
 		auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
@@ -608,6 +627,7 @@
 	certificate_t *cert = NULL;
 	x509_t *x509;
 	bool loose_gateway_id = FALSE;
+	int32_t custom_dpd = 0;
 	ike_cfg_create_t ike = {
 		.version = IKEV2,
 		.local = "%any",
@@ -618,7 +638,6 @@
 	peer_cfg_create_t peer = {
 		.cert_policy = CERT_SEND_IF_ASKED,
 		.unique = UNIQUE_REPLACE,
-		.keyingtries = 1,
 		.rekey_time = 36000, /* 10h */
 		.jitter_time = 600, /* 10min */
 		.over_time = 600, /* 10min */
@@ -630,8 +649,15 @@
 				.rekey = 10200 /* 2h50min */,
 				.jitter = 300 /* 5min */
 			},
+			.bytes = {
+				.life = 11000000000000 /* ~10TB */,
+				.rekey = 10000000000000 /* ~9TB */,
+				.jitter = 1000000000000 /* ~1TB */
+			},
 		},
 		.mode = MODE_TUNNEL,
+		.dpd_action = ACTION_RESTART,
+		.close_action = ACTION_RESTART,
 	};
 
 	/**
@@ -670,11 +696,28 @@
 	str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
 	child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
 
+	// dpd
+	str = nm_setting_vpn_get_data_item(vpn, "dpd-delay");
+	if (str && strlen(str))
+	{
+		if ( (custom_dpd = atoi(str)) > 0)
+		{
+			peer.dpd = custom_dpd;
+		}
+	}
+
 	/**
 	 * Register credentials
 	 */
 	priv->creds->clear(priv->creds);
 
+	/* preinstalled CRLs */
+	str = nm_setting_vpn_get_data_item(vpn, "crl-dir");
+	if (str && strlen(str))
+	{
+		priv->creds->load_crl_dir(priv->creds, str);
+	}
+
 	/* gateway/CA cert */
 	str = nm_setting_vpn_get_data_item(vpn, "certificate");
 	if (str)
@@ -766,7 +809,8 @@
 		streq(method, "eap-tls") ||
 		streq(method, "key") ||
 		streq(method, "agent") ||
-		streq(method, "smartcard"))
+		streq(method, "smartcard") ||
+		streq(method, "eap-bsts"))
 	{
 		if (!add_auth_cfg_cert (priv, vpn, peer_cfg, err))
 		{
@@ -777,7 +821,8 @@
 		}
 	}
 	else if (streq(method, "eap") ||
-			 streq(method, "psk"))
+			 streq(method, "psk") ||
+			 streq(method, "eap-bpace"))
 	{
 		if (!add_auth_cfg_pw(priv, vpn, peer_cfg, err))
 		{
@@ -839,10 +884,34 @@
 	}
 	ts = traffic_selector_create_dynamic(0, 0, 65535);
 	child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
-	ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
-	child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
-	ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
-	child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+	str = nm_setting_vpn_get_data_item(vpn, "remote-ts");
+	if (str && strlen(str))
+	{
+		enumerator = enumerator_create_token(str, ";", "");
+		while (enumerator->enumerate(enumerator, &str))
+		{
+			ts = traffic_selector_create_from_cidr((char*)str, 0, 0, 65535);
+			if (!ts)
+			{
+				g_set_error(err, NM_VPN_PLUGIN_ERROR,
+							NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+							"Invalid remote traffic selector.");
+				enumerator->destroy(enumerator);
+				child_cfg->destroy(child_cfg);
+				peer_cfg->destroy(peer_cfg);
+				return FALSE;
+			}
+			child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+		}
+		enumerator->destroy(enumerator);
+	}
+	else
+	{
+		ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
+		child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+		ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
+		child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+	}
 	peer_cfg->add_child_cfg(peer_cfg, child_cfg);
 
 	/**
@@ -893,7 +962,7 @@
 							 const char **setting_name, GError **error)
 {
 	NMSettingVpn *settings;
-	const char *method, *cert_source, *path;
+	const char *method, *cert_source, *userkey_source, *path;
 	bool need_secret = FALSE;
 
 	settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
@@ -905,9 +974,11 @@
 			streq(method, "eap-tls") ||
 			streq(method, "key") ||
 			streq(method, "agent") ||
-			streq(method, "smartcard"))
+			streq(method, "smartcard") ||
+			streq(method, "eap-bsts"))
 		{
 			cert_source = nm_setting_vpn_get_data_item(settings, "cert-source");
+			userkey_source = nm_setting_vpn_get_data_item(settings, "userkey-source");
 			if (!cert_source)
 			{
 				cert_source = method;
@@ -920,6 +991,10 @@
 			{
 				need_secret = !nm_setting_vpn_get_secret(settings, "password");
 			}
+			else if (userkey_source)
+			{
+				need_secret = !nm_setting_vpn_get_secret(settings, "password");
+			}
 			else
 			{
 				need_secret = TRUE;
@@ -944,7 +1019,8 @@
 			}
 		}
 		else if (streq(method, "eap") ||
-				 streq(method, "psk"))
+				 streq(method, "psk") ||
+				 streq(method, "eap-bpace"))
 		{
 			need_secret = !nm_setting_vpn_get_secret(settings, "password");
 		}
@@ -974,6 +1050,11 @@
 			enumerator->destroy(enumerator);
 			charon->controller->terminate_ike(charon->controller, id, FALSE,
 											  controller_cb_empty, NULL, 0);
+
+			/* clear secrets as we are asked for new secrets (where we'd find
+			 * the cached secrets from earlier connections) before we clear
+			 * them in connect() */
+			priv->creds->clear(priv->creds);
 			return FALSE;
 		}
 	}
diff -ruN strongswan-5.8.4/src/charon-nm/nm/nm_service.h strongswancont-5.8.4-svc/src/charon-nm/nm/nm_service.h
--- strongswan-5.8.4/src/charon-nm/nm/nm_service.h	2018-10-04 00:35:16.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/nm/nm_service.h	2022-07-06 15:47:33.746967000 +0300
@@ -35,9 +35,9 @@
 #define NM_IS_STRONGSWAN_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_STRONGSWAN_PLUGIN))
 #define NM_STRONGSWAN_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginClass))
 
-#define NM_DBUS_SERVICE_STRONGSWAN    "org.freedesktop.NetworkManager.strongswan"
-#define NM_DBUS_INTERFACE_STRONGSWAN  "org.freedesktop.NetworkManager.strongswan"
-#define NM_DBUS_PATH_STRONGSWAN       "/org/freedesktop/NetworkManager/strongswan"
+#define NM_DBUS_SERVICE_STRONGSWAN    "org.freedesktop.NetworkManager.strongswancont"
+#define NM_DBUS_INTERFACE_STRONGSWAN  "org.freedesktop.NetworkManager.strongswancont"
+#define NM_DBUS_PATH_STRONGSWAN       "/org/freedesktop/NetworkManager/strongswancont"
 
 typedef struct {
 	NMVpnServicePlugin parent;
diff -ruN strongswan-5.8.4/src/charon-nm/nm-strongswancont-service.conf strongswancont-5.8.4-svc/src/charon-nm/nm-strongswancont-service.conf
--- strongswan-5.8.4/src/charon-nm/nm-strongswancont-service.conf	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/nm-strongswancont-service.conf	2022-07-06 15:47:33.758967000 +0300
@@ -0,0 +1,15 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+	<policy user="root">
+		<allow own="org.freedesktop.NetworkManager.strongswancont"/>
+		<allow send_destination="org.freedesktop.NetworkManager.strongswancont"/>
+		<allow send_interface="org.freedesktop.NetworkManager.strongswancont"/>
+	</policy>
+	<policy context="default">
+		<deny own="org.freedesktop.NetworkManager.strongswancont"/>
+		<deny send_destination="org.freedesktop.NetworkManager.strongswancont"/>
+	</policy>
+</busconfig>
+
diff -ruN strongswan-5.8.4/src/charon-nm/nm-strongswan-service.conf strongswancont-5.8.4-svc/src/charon-nm/nm-strongswan-service.conf
--- strongswan-5.8.4/src/charon-nm/nm-strongswan-service.conf	2016-09-27 11:40:31.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-nm/nm-strongswan-service.conf	1970-01-01 03:00:00.000000000 +0300
@@ -1,15 +0,0 @@
-<!DOCTYPE busconfig PUBLIC
- "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-	<policy user="root">
-		<allow own="org.freedesktop.NetworkManager.strongswan"/>
-		<allow send_destination="org.freedesktop.NetworkManager.strongswan"/>
-		<allow send_interface="org.freedesktop.NetworkManager.strongswan"/>
-	</policy>
-	<policy context="default">
-		<deny own="org.freedesktop.NetworkManager.strongswan"/>
-		<deny send_destination="org.freedesktop.NetworkManager.strongswan"/>
-	</policy>
-</busconfig>
-
diff -ruN strongswan-5.8.4/src/charon-svc/charon-svc.c strongswancont-5.8.4-svc/src/charon-svc/charon-svc.c
--- strongswan-5.8.4/src/charon-svc/charon-svc.c	2018-05-28 14:30:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/charon-svc/charon-svc.c	2022-12-08 15:26:17.088850000 +0300
@@ -68,7 +68,7 @@
 }
 
 /**
- * Log strongSwan/Windows version during startup
+ * Log strongSwanCont/Windows version during startup
  */
 static void print_version()
 {
@@ -79,7 +79,7 @@
 
 	if (GetVersionEx((LPOSVERSIONINFO)&osvie))
 	{
-		DBG1(DBG_DMN, "Starting IKE service %s (strongSwan %s, "
+		DBG1(DBG_DMN, "Starting IKE service %s (strongSwanCont %s, "
 			 "Windows %s %d.%d.%d (SP %d.%d)", SERVICE_NAME, VERSION,
 			 osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server",
 			 osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
Двоичные файлы strongswan-5.8.4/src/charon-svc/charon-svc.exe и strongswancont-5.8.4-svc/src/charon-svc/charon-svc.exe различаются
diff -ruN strongswan-5.8.4/src/include/linux/pfkeyv2.h strongswancont-5.8.4-svc/src/include/linux/pfkeyv2.h
--- strongswan-5.8.4/src/include/linux/pfkeyv2.h	2016-04-22 23:01:35.000000000 +0300
+++ strongswancont-5.8.4-svc/src/include/linux/pfkeyv2.h	2022-07-06 15:47:33.766967000 +0300
@@ -296,6 +296,10 @@
 #define SADB_X_AALG_SHA2_512HMAC	7
 #define SADB_X_AALG_RIPEMD160HMAC	8
 #define SADB_X_AALG_AES_XCBC_MAC	9
+#define SADB_X_AALG_BELT_HASH		10
+#define SADB_X_AALG_GOST_MAC		11
+#define SADB_X_AALG_BELT_MAC		12
+#define SADB_X_AALG_BELT_HMAC		13
 #define SADB_X_AALG_NULL		251	/* kame */
 #define SADB_AALG_MAX			251
 
@@ -316,6 +320,13 @@
 #define SADB_X_EALG_AES_GCM_ICV16	20
 #define SADB_X_EALG_CAMELLIACBC		22
 #define SADB_X_EALG_NULL_AES_GMAC	23
+#define SADB_X_EALG_GOST28147_ECB	24
+#define SADB_X_EALG_GOST28147_CTR	25
+#define SADB_X_EALG_GOST28147_CFB	26 
+#define SADB_X_EALG_BELT_ECB		27 
+#define SADB_X_EALG_BELT_CBC		28 
+#define SADB_X_EALG_BELT_CFB		29 
+#define SADB_X_EALG_BELT_CTR		30 
 #define SADB_EALG_MAX                   253 /* last EALG */
 /* private allocations should use 249-255 (RFC2407) */
 #define SADB_X_EALG_SERPENTCBC  252     /* draft-ietf-ipsec-ciph-aes-cbc-00 */
diff -ruN strongswan-5.8.4/src/ipsec/_ipsec.8.in strongswancont-5.8.4-svc/src/ipsec/_ipsec.8.in
--- strongswan-5.8.4/src/ipsec/_ipsec.8.in	2018-10-23 20:03:28.000000000 +0300
+++ strongswancont-5.8.4-svc/src/ipsec/_ipsec.8.in	2022-07-06 15:47:33.782967000 +0300
@@ -1,4 +1,4 @@
-.TH @IPSEC_SCRIPT_UPPER@ 8 "2013-10-29" "@IPSEC_VERSION@" "strongSwan"
+.TH @IPSEC_SCRIPT_UPPER@ 8 "2013-10-29" "@IPSEC_VERSION@" "strongSwanCont"
 .
 .SH NAME
 .
@@ -277,15 +277,15 @@
 .TP
 .B "\-\-version"
 returns the version in the form of
-.B Linux strongSwan U<strongSwan userland version>/K<Linux kernel version>
-if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is
+.B Linux strongSwanCont U<strongSwanCont userland version>/K<Linux kernel version>
+if strongSwanCont uses the native NETKEY IPsec stack of the Linux kernel it is
 running on.
 .
 .TP
 .B "\-\-versioncode"
 returns the version number in the form of
-.B U<strongSwan userland version>/K<Linux kernel version>
-if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is
+.B U<strongSwanCont userland version>/K<Linux kernel version>
+if strongSwanCont uses the native NETKEY IPsec stack of the Linux kernel it is
 running on.
 .
 .TP
diff -ruN strongswan-5.8.4/src/ipsec/_ipsec.in strongswancont-5.8.4-svc/src/ipsec/_ipsec.in
--- strongswan-5.8.4/src/ipsec/_ipsec.in	2019-08-27 16:27:26.000000000 +0300
+++ strongswancont-5.8.4-svc/src/ipsec/_ipsec.in	2022-07-06 15:47:33.782967000 +0300
@@ -42,7 +42,7 @@
 
 export IPSEC_DIR IPSEC_BINDIR IPSEC_SBINDIR IPSEC_CONFDIR IPSEC_PIDDIR IPSEC_SCRIPT IPSEC_VERSION IPSEC_NAME IPSEC_STARTER_PID IPSEC_CHARON_PID
 
-IPSEC_DISTRO="University of Applied Sciences Rapperswil, Switzerland"
+IPSEC_DISTRO="STC Contact\nMinsk, Belarus"
 
 command_dir="$IPSEC_DIR"
 
@@ -171,10 +171,10 @@
 	rc=7
 	if [ -e $IPSEC_STARTER_PID ]
 	then
-		echo "Reloading strongSwan IPsec configuration..." >&2
+		echo "Reloading strongSwanCont IPsec configuration..." >&2
 		kill -USR1 `cat $IPSEC_STARTER_PID` 2>/dev/null && rc=0
 	else
-		echo "Reloading strongSwan IPsec failed: starter is not running" >&2
+		echo "Reloading strongSwanCont IPsec failed: starter is not running" >&2
 	fi
 	exit "$rc"
 	;;
@@ -249,7 +249,7 @@
 	# stopping a not-running service is considered as success
 	if [ -e $IPSEC_STARTER_PID ]
 	then
-		echo "Stopping strongSwan IPsec..." >&2
+		echo "Stopping strongSwanCont IPsec..." >&2
 		spid=`cat $IPSEC_STARTER_PID`
 		if [ -n "$spid" ]
 		then
@@ -272,7 +272,7 @@
 			fi
 		fi
 	else
-		echo "Stopping strongSwan IPsec failed: starter is not running" >&2
+		echo "Stopping strongSwanCont IPsec failed: starter is not running" >&2
 	fi
 	if [ -d /var/lock/subsys ]; then
 		rm -f /var/lock/subsys/ipsec
@@ -297,11 +297,11 @@
 update)
 	if [ -e $IPSEC_STARTER_PID ]
 	then
-		echo "Updating strongSwan IPsec configuration..." >&2
+		echo "Updating strongSwanCont IPsec configuration..." >&2
 		kill -HUP `cat $IPSEC_STARTER_PID`
 		exit 0
 	else
-		echo "Updating strongSwan IPsec failed: starter is not running" >&2
+		echo "Updating strongSwanCont IPsec failed: starter is not running" >&2
 		exit 7
 	fi
 	;;
diff -ruN strongswan-5.8.4/src/libcharon/bus/listeners/file_logger.c strongswancont-5.8.4-svc/src/libcharon/bus/listeners/file_logger.c
--- strongswan-5.8.4/src/libcharon/bus/listeners/file_logger.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/bus/listeners/file_logger.c	2022-07-06 15:47:33.786967000 +0300
@@ -243,6 +243,25 @@
 				 this->filename, strerror(errno));
 			return;
 		}
+#ifdef HAVE_CHOWN
+		if (lib->caps->check(lib->caps, CAP_CHOWN))
+		{
+			if (chown(this->filename, lib->caps->get_uid(lib->caps),
+					  lib->caps->get_gid(lib->caps)) != 0)
+			{
+				DBG1(DBG_NET, "changing owner/group for '%s' failed: %s",
+					 this->filename, strerror(errno));
+			}
+		}
+		else
+		{
+			if (chown(this->filename, -1, lib->caps->get_gid(lib->caps)) != 0)
+			{
+				DBG1(DBG_NET, "changing group for '%s' failed: %s",
+					 this->filename, strerror(errno));
+			}
+		}
+#endif /* HAVE_CHOWN */
 #ifdef HAVE_SETLINEBUF
 		if (flush_line)
 		{
diff -ruN strongswan-5.8.4/src/libcharon/config/ike_cfg.c strongswancont-5.8.4-svc/src/libcharon/config/ike_cfg.c
--- strongswan-5.8.4/src/libcharon/config/ike_cfg.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/config/ike_cfg.c	2023-05-13 16:23:12.316906000 +0300
@@ -119,6 +119,13 @@
 	 * List of proposals to use
 	 */
 	linked_list_t *proposals;
+
+#ifdef _WIN32
+	/**
+	 * should we use block dns?
+	 */
+	bool block_dns;
+#endif /* _WIN32 */
 };
 
 METHOD(ike_cfg_t, get_version, ike_version_t,
@@ -151,6 +158,14 @@
 	return this->childless;
 }
 
+#ifdef _WIN32
+METHOD(ike_cfg_t, block_dns_, bool,
+	private_ike_cfg_t *this)
+{
+	return this->block_dns;
+}
+#endif /* _WIN32 */
+
 /**
  * Common function for resolve_me/other
  */
@@ -603,6 +618,9 @@
 			.select_proposal = _select_proposal,
 			.has_proposal = _has_proposal,
 			.get_dh_group = _get_dh_group,
+#ifdef _WIN32
+			.block_dns = _block_dns_,
+#endif /* _WIN32 */
 			.equals = _equals,
 			.get_ref = _get_ref,
 			.destroy = _destroy,
@@ -623,6 +641,9 @@
 		.other_port = data->remote_port,
 		.dscp = data->dscp,
 		.proposals = linked_list_create(),
+#ifdef _WIN32
+		.block_dns = data->block_dns,
+#endif /* _WIN32 */
 	);
 
 	parse_addresses(data->local, this->my_hosts, this->my_ranges);
diff -ruN strongswan-5.8.4/src/libcharon/config/ike_cfg.h strongswancont-5.8.4-svc/src/libcharon/config/ike_cfg.h
--- strongswan-5.8.4/src/libcharon/config/ike_cfg.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/config/ike_cfg.h	2023-05-13 16:24:21.778641000 +0300
@@ -236,6 +236,15 @@
 	 */
 	diffie_hellman_group_t (*get_dh_group)(ike_cfg_t *this);
 
+#ifdef _WIN32
+	/**
+	 * Should we use block DNS?
+	 *
+	 * @return				TRUE to block DNS
+	 */
+	bool (*block_dns) (ike_cfg_t *this);
+#endif /* _WIN32 */
+
 	/**
 	 * Check if two IKE configs are equal.
 	 *
@@ -289,6 +298,10 @@
 	childless_t childless;
 	/** DSCP value to send IKE packets with */
 	uint8_t dscp;
+#ifdef _WIN32
+	/** TRUE to use block DNS */
+	bool block_dns;
+#endif /* _WIN32 */
 };
 
 /**
diff -ruN strongswan-5.8.4/src/libcharon/encoding/payloads/certreq_payload.c strongswancont-5.8.4-svc/src/libcharon/encoding/payloads/certreq_payload.c
--- strongswan-5.8.4/src/libcharon/encoding/payloads/certreq_payload.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/encoding/payloads/certreq_payload.c	2022-07-06 15:47:33.830968000 +0300
@@ -116,9 +116,9 @@
 	{
 		if (this->data.len % HASH_SIZE_SHA1)
 		{
-			DBG1(DBG_ENC, "invalid X509 hash length (%d) in certreq",
+			DBG1(DBG_ENC, "unknown X509 hash length (%d) in certreq",
 				 this->data.len);
-			return FAILED;
+			return SUCCESS;
 		}
 	}
 	return SUCCESS;
diff -ruN strongswan-5.8.4/src/libcharon/encoding/payloads/proposal_substructure.c strongswancont-5.8.4-svc/src/libcharon/encoding/payloads/proposal_substructure.c
--- strongswan-5.8.4/src/libcharon/encoding/payloads/proposal_substructure.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/encoding/payloads/proposal_substructure.c	2022-07-06 15:47:33.834968000 +0300
@@ -174,6 +174,12 @@
 	/* FreeS/WAN proprietary */
 	IKEV1_ENCR_SERPENT_CBC = 65004,
 	IKEV1_ENCR_TWOFISH_CBC = 65005,
+	/* BY specific */
+	IKEV1_ENCR_GOST28147_CFB = 65530,
+	IKEV1_ENCR_GOST28147_CTR = 65531,
+	IKEV1_ENCR_BELT_CFB = 65532,
+	IKEV1_ENCR_BELT_CBC = 65533,
+	IKEV1_ENCR_BELT_CTR = 65534,
 } ikev1_encryption_t;
 
 /**
@@ -186,6 +192,11 @@
 	IKEV1_HASH_SHA2_256 = 4,
 	IKEV1_HASH_SHA2_384 = 5,
 	IKEV1_HASH_SHA2_512 = 6,
+	/* BY specific */
+	IKEV1_GOST_MAC = 65529,
+	IKEV1_BELT_MAC = 65530,
+	IKEV1_BELT_HMAC = 65531,
+	IKEV1_BELT_HASH = 65532,
 } ikev1_hash_t;
 
 /**
@@ -222,8 +233,14 @@
 	IKEV1_ESP_ENCR_CAMELLIA = 22,
 	IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC = 23,
 	/* FreeS/WAN proprietary */
-	IKEV1_ESP_ENCR_SERPENT = 252,
+	IKEV1_ESP_ENCR_SERPENT = 251,
 	IKEV1_ESP_ENCR_TWOFISH = 253,
+	/* BY specific */
+	IKEV1_ESP_ENCR_GOST28147_CTR = 249,
+	IKEV1_ESP_ENCR_GOST28147_CFB = 250,
+	IKEV1_ESP_ENCR_BELT_CFB = 252,
+	IKEV1_ESP_ENCR_BELT_CBC = 254,
+	IKEV1_ESP_ENCR_BELT_CTR = 255,
 } ikev1_esp_transid_t;
 
 /**
@@ -242,6 +259,11 @@
 	IKEV1_AH_AES_128_GMAC = 11,
 	IKEV1_AH_AES_192_GMAC = 12,
 	IKEV1_AH_AES_256_GMAC = 13,
+	/* BY specific */
+	IKEV1_AH_GOST_MAC = 65531,
+	IKEV1_AH_BELT_MAC = 65532,
+	IKEV1_AH_BELT_HMAC = 65533,
+	IKEV1_AH_BELT_HASH = 65534,
 } ikev1_ah_transid_t;
 
 /**
@@ -261,6 +283,11 @@
 	IKEV1_AUTH_AES_128_GMAC = 11,
 	IKEV1_AUTH_AES_192_GMAC = 12,
 	IKEV1_AUTH_AES_256_GMAC = 13,
+	/* BY specific */
+	IKEV1_ESP_AUTH_GOST_MAC = 65531,
+	IKEV1_ESP_AUTH_BELT_MAC = 65532,
+	IKEV1_ESP_AUTH_BELT_HMAC = 65533,
+	IKEV1_ESP_AUTH_BELT_HASH = 65534,
 } ikev1_auth_algo_t;
 
 /**
@@ -311,6 +338,8 @@
 	IKEV1_AUTH_HYBRID_RESP_RSA = 64222,
 	IKEV1_AUTH_HYBRID_INIT_DSS = 64223,
 	IKEV1_AUTH_HYBRID_RESP_DSS = 64224,
+	/* BIGN */
+	IKEV1_AUTH_BIGN = 65201,
 } ikev1_auth_method_t;
 
 /**
@@ -591,6 +620,11 @@
 	{ IKEV1_ENCR_CAST_CBC,		ENCR_CAST },
 	{ IKEV1_ENCR_AES_CBC,		ENCR_AES_CBC },
 	{ IKEV1_ENCR_CAMELLIA_CBC,	ENCR_CAMELLIA_CBC },
+	{ IKEV1_ENCR_GOST28147_CTR,	ENCR_GOST28147_CTR },
+	{ IKEV1_ENCR_GOST28147_CFB,	ENCR_GOST28147_CFB },
+	{ IKEV1_ENCR_BELT_CBC,		ENCR_BELT_CBC },
+	{ IKEV1_ENCR_BELT_CFB,		ENCR_BELT_CFB },
+	{ IKEV1_ENCR_BELT_CTR,		ENCR_BELT_CTR },
 	{ IKEV1_ENCR_SERPENT_CBC,	ENCR_SERPENT_CBC },
 	{ IKEV1_ENCR_TWOFISH_CBC,	ENCR_TWOFISH_CBC },
 };
@@ -604,6 +638,10 @@
 	{ IKEV1_HASH_SHA2_256,		AUTH_HMAC_SHA2_256_128 },
 	{ IKEV1_HASH_SHA2_384,		AUTH_HMAC_SHA2_384_192 },
 	{ IKEV1_HASH_SHA2_512,		AUTH_HMAC_SHA2_512_256 },
+	{ IKEV1_BELT_HASH,			AUTH_BELT_HASH },
+	{ IKEV1_GOST_MAC,			AUTH_GOST_MAC },
+	{ IKEV1_BELT_MAC,			AUTH_BELT_MAC },
+	{ IKEV1_BELT_HMAC,			AUTH_BELT_HMAC },
 };
 
 /**
@@ -615,6 +653,7 @@
 	{ IKEV1_HASH_SHA2_256,		PRF_HMAC_SHA2_256 },
 	{ IKEV1_HASH_SHA2_384,		PRF_HMAC_SHA2_384 },
 	{ IKEV1_HASH_SHA2_512,		PRF_HMAC_SHA2_512 },
+	{ IKEV1_BELT_HASH,			PRF_HMAC_HBELT }
 };
 
 /**
@@ -641,6 +680,11 @@
 	{ IKEV1_ESP_ENCR_AES_GCM_16,			ENCR_AES_GCM_ICV16 },
 	{ IKEV1_ESP_ENCR_CAMELLIA,				ENCR_CAMELLIA_CBC },
 	{ IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC,	ENCR_NULL_AUTH_AES_GMAC },
+	{ IKEV1_ESP_ENCR_GOST28147_CTR,			ENCR_GOST28147_CTR },
+	{ IKEV1_ESP_ENCR_GOST28147_CFB,			ENCR_GOST28147_CFB },
+	{ IKEV1_ESP_ENCR_BELT_CBC,				ENCR_BELT_CBC },
+	{ IKEV1_ESP_ENCR_BELT_CFB,				ENCR_BELT_CFB },
+	{ IKEV1_ESP_ENCR_BELT_CTR,				ENCR_BELT_CTR },
 	{ IKEV1_ESP_ENCR_SERPENT,				ENCR_SERPENT_CBC },
 	{ IKEV1_ESP_ENCR_TWOFISH,				ENCR_TWOFISH_CBC },
 };
@@ -659,6 +703,10 @@
 	{ IKEV1_AH_AES_128_GMAC,	AUTH_AES_128_GMAC },
 	{ IKEV1_AH_AES_192_GMAC,	AUTH_AES_192_GMAC },
 	{ IKEV1_AH_AES_256_GMAC,	AUTH_AES_256_GMAC },
+	{ IKEV1_AH_BELT_HASH,		AUTH_BELT_HASH },
+	{ IKEV1_AH_GOST_MAC,		AUTH_GOST_MAC },
+	{ IKEV1_AH_BELT_MAC,		AUTH_BELT_MAC },
+	{ IKEV1_AH_BELT_HMAC,		AUTH_BELT_HMAC },
 };
 
 /**
@@ -676,6 +724,10 @@
 	{ IKEV1_AUTH_AES_128_GMAC,		AUTH_AES_128_GMAC },
 	{ IKEV1_AUTH_AES_192_GMAC,		AUTH_AES_192_GMAC },
 	{ IKEV1_AUTH_AES_256_GMAC,		AUTH_AES_256_GMAC },
+	{ IKEV1_ESP_AUTH_BELT_HASH,		AUTH_BELT_HASH },
+	{ IKEV1_ESP_AUTH_GOST_MAC,		AUTH_GOST_MAC },
+	{ IKEV1_ESP_AUTH_BELT_MAC,		AUTH_BELT_MAC },
+	{ IKEV1_ESP_AUTH_BELT_HMAC,		AUTH_BELT_HMAC },
 };
 
 /**
@@ -833,6 +885,8 @@
 			return IKEV1_AUTH_ECDSA_384;
 		case AUTH_ECDSA_521:
 			return IKEV1_AUTH_ECDSA_521;
+		case AUTH_BIGN:
+			return IKEV1_AUTH_BIGN;
 		case AUTH_PSK:
 		default:
 			return IKEV1_AUTH_PSK;
@@ -1186,6 +1240,8 @@
 			return AUTH_ECDSA_384;
 		case IKEV1_AUTH_ECDSA_521:
 			return AUTH_ECDSA_521;
+		case IKEV1_AUTH_BIGN:
+			return AUTH_BIGN;
 		default:
 			return AUTH_NONE;
 	}
@@ -1506,6 +1562,16 @@
 		add_transform_substructure(this, transform);
 	}
 	enumerator->destroy(enumerator);
+
+	/* key transform algorithms (keyrep) */
+	enumerator = proposal->create_enumerator(proposal, KEY_TRANSFORM_ALGORITHM);
+	while (enumerator->enumerate(enumerator, &alg, NULL))
+	{
+		transform = transform_substructure_create_type(PLV2_TRANSFORM_SUBSTRUCTURE,
+												KEY_TRANSFORM_ALGORITHM, alg);
+		add_transform_substructure(this, transform);
+	}
+	enumerator->destroy(enumerator);
 }
 
 /**
diff -ruN strongswan-5.8.4/src/libcharon/plugins/eap_gtc/eap_gtc.c strongswancont-5.8.4-svc/src/libcharon/plugins/eap_gtc/eap_gtc.c
--- strongswan-5.8.4/src/libcharon/plugins/eap_gtc/eap_gtc.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/eap_gtc/eap_gtc.c	2022-07-06 15:47:33.850968000 +0300
@@ -195,7 +195,7 @@
 METHOD(eap_method_t, get_msk, status_t,
 	private_eap_gtc_t *this, chunk_t *msk)
 {
-	return FAILED;
+	return NOT_SUPPORTED;
 }
 
 METHOD(eap_method_t, get_identifier, uint8_t,
diff -ruN strongswan-5.8.4/src/libcharon/plugins/eap_md5/eap_md5.c strongswancont-5.8.4-svc/src/libcharon/plugins/eap_md5/eap_md5.c
--- strongswan-5.8.4/src/libcharon/plugins/eap_md5/eap_md5.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/eap_md5/eap_md5.c	2022-07-06 15:47:33.866969000 +0300
@@ -213,7 +213,7 @@
 METHOD(eap_method_t, get_msk, status_t,
 	private_eap_md5_t *this, chunk_t *msk)
 {
-	return FAILED;
+	return NOT_SUPPORTED;
 }
 
 METHOD(eap_method_t, is_mutual, bool,
diff -ruN strongswan-5.8.4/src/libcharon/plugins/eap_radius/eap_radius.c strongswancont-5.8.4-svc/src/libcharon/plugins/eap_radius/eap_radius.c
--- strongswan-5.8.4/src/libcharon/plugins/eap_radius/eap_radius.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/eap_radius/eap_radius.c	2022-07-06 15:47:33.874969000 +0300
@@ -733,7 +733,9 @@
 		*out = msk;
 		return SUCCESS;
 	}
-	return FAILED;
+	/* we assume the selected method did not establish an MSK, if it failed
+	 * to establish one, process() would have failed */
+	return NOT_SUPPORTED;
 }
 
 METHOD(eap_method_t, get_identifier, uint8_t,
diff -ruN strongswan-5.8.4/src/libcharon/plugins/kernel_iph/kernel_iph_net.c strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_iph/kernel_iph_net.c
--- strongswan-5.8.4/src/libcharon/plugins/kernel_iph/kernel_iph_net.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_iph/kernel_iph_net.c	2023-06-15 15:40:59.955019000 +0300
@@ -77,6 +77,26 @@
 };
 
 /**
+ * Interface address entry
+ */
+typedef struct {
+	/** address */
+	host_t *ip;
+	/** is virtual installed by us? */
+	bool virtual;
+} addr_t;
+
+/**
+ * Clean up an addr_t
+ */
+CALLBACK(addr_destroy, void,
+	addr_t *this)
+{
+	this->ip->destroy(this->ip);
+	free(this);
+}
+
+/**
  * Interface entry
  */
 typedef struct  {
@@ -99,7 +119,7 @@
  */
 static void iface_destroy(iface_t *this)
 {
-	this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy));
+	this->addrs->destroy_function(this->addrs, addr_destroy);
 	free(this->ifname);
 	free(this->ifdesc);
 	free(this);
@@ -155,6 +175,70 @@
 }
 
 /**
+ * Add an address entry to a named interface, return ifindex
+ */
+static DWORD add_addr(private_kernel_iph_net_t *this, char *name, host_t *ip,
+					  bool virtual)
+{
+	enumerator_t *enumerator;
+	addr_t *addr;
+	iface_t *iface;
+	DWORD ifindex = 0;
+
+	this->mutex->lock(this->mutex);
+	enumerator = this->ifaces->create_enumerator(this->ifaces);
+	while (enumerator->enumerate(enumerator, &iface))
+	{
+		if (streq(name, iface->ifname))
+		{
+			INIT(addr,
+				.ip = ip->clone(ip),
+				.virtual = virtual,
+			);
+			iface->addrs->insert_last(iface->addrs, addr);
+			ifindex = iface->ifindex;
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->mutex->unlock(this->mutex);
+
+	return ifindex;
+}
+
+/**
+ * Remove address entry from named interface, return ifindex
+ */
+static DWORD remove_addr(private_kernel_iph_net_t *this, host_t *ip)
+{
+	enumerator_t *ifaces, *addrs;
+	iface_t *iface;
+	addr_t *addr;
+	DWORD ifindex = 0;
+
+	this->mutex->lock(this->mutex);
+	ifaces = this->ifaces->create_enumerator(this->ifaces);
+	while (!ifindex && ifaces->enumerate(ifaces, &iface))
+	{
+		addrs = iface->addrs->create_enumerator(iface->addrs);
+		while (!ifindex && addrs->enumerate(addrs, &addr))
+		{
+			if (ip->ip_equals(ip, addr->ip))
+			{
+				iface->addrs->remove_at(iface->addrs, addrs);
+				addr_destroy(addr);
+				ifindex = iface->ifindex;
+			}
+		}
+		addrs->destroy(addrs);
+	}
+	ifaces->destroy(ifaces);
+	this->mutex->unlock(this->mutex);
+
+	return ifindex;
+}
+
+/**
  * Update addresses for an iface entry
  */
 static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
@@ -163,7 +247,8 @@
 	IP_ADAPTER_UNICAST_ADDRESS *current;
 	enumerator_t *enumerator;
 	linked_list_t *list;
-	host_t *host, *old;
+	host_t *host;
+	addr_t *aentry;
 	bool changes = FALSE;
 
 	list = entry->addrs;
@@ -185,21 +270,27 @@
 		host = host_create_from_sockaddr(current->Address.lpSockaddr);
 		if (host)
 		{
-			bool found = FALSE;
+			addr_t *found = FALSE;
 
 			enumerator = list->create_enumerator(list);
-			while (enumerator->enumerate(enumerator, &old))
+			while (enumerator->enumerate(enumerator, &aentry))
 			{
-				if (host->ip_equals(host, old))
+				if (host->ip_equals(host, aentry->ip))
 				{
 					list->remove_at(list, enumerator);
-					old->destroy(old);
-					found = TRUE;
+					found = aentry;
+					break;
 				}
 			}
 			enumerator->destroy(enumerator);
 
-			entry->addrs->insert_last(entry->addrs, host);
+			if (!found)
+			{
+				INIT(found,
+					.ip = host->clone(host),
+				);
+			}
+			entry->addrs->insert_last(entry->addrs, found);
 
 			if (!found && log)
 			{
@@ -207,18 +298,19 @@
 					 host, entry->ifindex, entry->ifdesc);
 				changes = TRUE;
 			}
+			host->destroy(host);
 		}
 	}
 
-	while (list->remove_first(list, (void**)&old) == SUCCESS)
+	while (list->remove_first(list, (void**)&aentry) == SUCCESS)
 	{
 		if (log)
 		{
 			DBG1(DBG_KNL, "%H disappeared from interface %u '%s'",
-				 old, entry->ifindex, entry->ifdesc);
+				 aentry->ip, entry->ifindex, entry->ifdesc);
 			changes = TRUE;
 		}
-		old->destroy(old);
+		addr_destroy(aentry);
 	}
 	list->destroy(list);
 
@@ -362,6 +454,8 @@
 	MIB_IPINTERFACE_ROW_FIXUP* row = (MIB_IPINTERFACE_ROW_FIXUP*)row_badal;
 	IP_ADAPTER_ADDRESSES addrs[64], *current;
 	ULONG res, size = sizeof(addrs);
+	char buf[512];
+	DBG1(DBG_KNL, "Received NotifyIpInterfaceChange callback");
 
 	if (row && type == MibDeleteInstance)
 	{
@@ -401,7 +495,7 @@
 		}
 		else
 		{
-			DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx", res);
+			DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx (%s)", res, human_readable_error(buf, res, sizeof(buf)));
 		}
 	}
 }
@@ -413,15 +507,15 @@
 {
 	enumerator_t *ifaces, *addrs;
 	iface_t *entry, *found = NULL;
-	host_t *host;
+	addr_t *addr;
 
 	ifaces = this->ifaces->create_enumerator(this->ifaces);
 	while (!found && ifaces->enumerate(ifaces, &entry))
 	{
 		addrs = entry->addrs->create_enumerator(entry->addrs);
-		while (!found && addrs->enumerate(addrs, &host))
+		while (!found && addrs->enumerate(addrs, &addr))
 		{
-			if (host->ip_equals(host, ip))
+			if (ip->ip_equals(ip, addr->ip))
 			{
 				found = entry;
 			}
@@ -433,6 +527,31 @@
 	return found;
 }
 
+/**
+ * Find an interface index by interface name
+ */
+static DWORD ifname2index(private_kernel_iph_net_t *this, char *name)
+{
+	enumerator_t *enumerator;
+	iface_t *entry;
+	DWORD ifindex = 0;
+
+	this->mutex->lock(this->mutex);
+	enumerator = this->ifaces->create_enumerator(this->ifaces);
+	while (enumerator->enumerate(enumerator, &entry))
+	{
+		if (streq(name, entry->ifname))
+		{
+			ifindex = entry->ifindex;
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->mutex->unlock(this->mutex);
+
+	return ifindex;
+}
+
 METHOD(kernel_net_t, get_interface_name, bool,
 	private_kernel_iph_net_t *this, host_t* ip, char **name)
 {
@@ -466,12 +585,10 @@
 } addr_enumerator_t;
 
 METHOD(enumerator_t, addr_enumerate, bool,
-	addr_enumerator_t *this, va_list args)
+	addr_enumerator_t *this, host_t **host)
 {
 	iface_t *entry;
-	host_t **host;
-
-	VA_ARGS_VGET(args, host);
+	addr_t *addr;
 
 	while (TRUE)
 	{
@@ -493,8 +610,13 @@
 			}
 			this->addrs = entry->addrs->create_enumerator(entry->addrs);
 		}
-		if (this->addrs->enumerate(this->addrs, host))
+		if (this->addrs->enumerate(this->addrs, &addr))
 		{
+			if (addr->virtual && (this->which & ADDR_TYPE_REGULAR))
+			{
+				continue;
+			}
+			*host = addr->ip;
 			return TRUE;
 		}
 		this->addrs->destroy(this->addrs);
@@ -502,7 +624,7 @@
 	}
 }
 
-METHOD(enumerator_t, addr_destroy, void,
+METHOD(enumerator_t, addr_enumerator_destroy, void,
 	addr_enumerator_t *this)
 {
 	DESTROY_IF(this->addrs);
@@ -516,19 +638,12 @@
 {
 	addr_enumerator_t *enumerator;
 
-	if (!(which & ADDR_TYPE_REGULAR))
-	{
-		/* we currently have no virtual, but regular IPs only */
-		return enumerator_create_empty();
-	}
-
 	this->mutex->lock(this->mutex);
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = enumerator_enumerate_default,
-			.venumerate = _addr_enumerate,
-			.destroy = _addr_destroy,
+			.enumerate = (void*)_addr_enumerate,
+			.destroy = _addr_enumerator_destroy,
 		},
 		.which = which,
 		.ifaces = this->ifaces->create_enumerator(this->ifaces),
@@ -608,18 +723,104 @@
 	return NULL;
 }
 
+/**
+ * Create a MIB unicast row from a host
+ */
+static void host2unicast(host_t *host, int prefix, MIB_UNICASTIPADDRESS_ROW *row)
+{
+	InitializeUnicastIpAddressEntry(row);
+
+	row->Address.si_family = host->get_family(host);
+	memcpy(&row->Address, host->get_sockaddr(host),
+		   *host->get_sockaddr_len(host));
+
+	row->PrefixOrigin = IpPrefixOriginOther;
+	row->SuffixOrigin = IpSuffixOriginOther;
+	/* don't change the default route to this address */
+	row->SkipAsSource = FALSE;
+	if (prefix == -1)
+	{
+		if (row->Address.si_family == AF_INET)
+		{
+			row->OnLinkPrefixLength = 32;
+		}
+		else
+		{
+			row->OnLinkPrefixLength = 128;
+		}
+	}
+	else
+	{
+		row->OnLinkPrefixLength = prefix;
+	}
+}
+
 METHOD(kernel_net_t, add_ip, status_t,
-	private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
-	char *iface_name)
+	private_kernel_iph_net_t *this, host_t *vip, int prefix, char *name)
 {
-	return NOT_SUPPORTED;
+	char buf[512];
+	MIB_UNICASTIPADDRESS_ROW row;
+	u_long status;
+
+	/* name of the MS Loopback adapter */
+	// name = "{DB2C49B1-7C90-4253-9E61-8C6A881194ED}";
+
+	if (!lib->settings->get_bool(lib->settings,
+					"%s.install_virtual_ip", TRUE, lib->ns)) {
+		return FAILED;
+	}
+
+	char *install_virtual_ip_on = lib->settings->get_str(lib->settings,
+					"%s.install_virtual_ip_on", NULL, lib->ns);
+
+	if (install_virtual_ip_on) {
+		name = install_virtual_ip_on;
+	}
+	host2unicast(vip, prefix, &row);
+
+	row.InterfaceIndex = add_addr(this, name, vip, TRUE);
+	if (!row.InterfaceIndex)
+	{
+		DBG1(DBG_KNL, "interface '%s' not found", name);
+		return NOT_FOUND;
+	}
+
+	status = CreateUnicastIpAddressEntry(&row);
+	if (status != NO_ERROR)
+	{
+		DBG1(DBG_KNL, "creating IPH address entry failed: %lu (%s)", status,
+			human_readable_error(buf, status, sizeof(buf)));
+		remove_addr(this, vip);
+		return FAILED;
+	}
+	return SUCCESS;
 }
 
 METHOD(kernel_net_t, del_ip, status_t,
-	private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
-	bool wait)
+	private_kernel_iph_net_t *this, host_t *vip, int prefix, bool wait)
 {
-	return NOT_SUPPORTED;
+	char buf[512];
+	MIB_UNICASTIPADDRESS_ROW row;
+	u_long status;
+
+	host2unicast(vip, prefix, &row);
+
+	row.InterfaceIndex = remove_addr(this, vip);
+	if (!row.InterfaceIndex)
+	{
+		DBG1(DBG_KNL, "virtual IP %H not found", vip);
+		return NOT_FOUND;
+	}
+
+	status = DeleteUnicastIpAddressEntry(&row);
+	if (status != NO_ERROR)
+	{
+		DBG1(DBG_KNL, "deleting IPH address entry failed: %lu (%s)", status,
+			human_readable_error(buf, status, sizeof(buf)));
+		return FAILED;
+	}
+
+	return SUCCESS;
 }
 
 /**
@@ -628,6 +829,7 @@
 static status_t manage_route(private_kernel_iph_net_t *this, bool add,
 					chunk_t dst, uint8_t prefixlen, host_t *gtw, char *name)
 {
+	char buf[512];
 	MIB_IPFORWARD_ROW2 row = {
 		.DestinationPrefix = {
 			.PrefixLength = prefixlen,
@@ -638,23 +840,30 @@
 		.Metric = 10,
 		.Protocol = MIB_IPPROTO_NETMGMT,
 	};
-	enumerator_t *enumerator;
-	iface_t *entry;
 	ULONG ret;
 
-	this->mutex->lock(this->mutex);
-	enumerator = this->ifaces->create_enumerator(this->ifaces);
-	while (enumerator->enumerate(enumerator, &entry))
+	/* if route is 0.0.0.0/0, we can't install it, as it would
+	 * overwrite the default route. Instead, we add two routes:
+	 * 0.0.0.0/1 and 128.0.0.0/1 */
+	if (prefixlen == 0)
 	{
-		if (streq(name, entry->ifname))
+		chunk_t half;
+		status_t status;
+
+		half = chunk_alloca(dst.len);
+		memset(half.ptr, 0, half.len);
+		prefixlen = 1;
+
+		status = manage_route(this, add, half, prefixlen, gtw, name);
+		if (status == SUCCESS)
 		{
-			row.InterfaceIndex = entry->ifindex;
-			break;
+			half.ptr[0] |= 0x80;
+			status = manage_route(this, add, half, prefixlen, gtw, name);
 		}
+		return status;
 	}
-	enumerator->destroy(enumerator);
-	this->mutex->unlock(this->mutex);
 
+	row.InterfaceIndex = ifname2index(this, name);
 	if (!row.InterfaceIndex)
 	{
 		return NOT_FOUND;
@@ -690,7 +899,8 @@
 	}
 	if (ret != NO_ERROR)
 	{
-		DBG1(DBG_KNL, "%sing route failed: 0x%08lx", add ? "add" : "remov", ret);
+		DBG1(DBG_KNL, "%sing route failed: 0x%08lx (%s)", add ? "add" : "remov", ret,
+			human_readable_error(buf, ret, sizeof(buf)));
 		return FAILED;
 	}
 
@@ -699,7 +909,8 @@
 		ret = EnableRouter(NULL, &this->router);
 		if (ret != ERROR_IO_PENDING)
 		{
-			DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx", ret);
+			DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx (%s)", ret,
+				human_readable_error(buf, ret, sizeof(buf)));
 		}
 	}
 	else
@@ -707,7 +918,8 @@
 		ret = UnenableRouter(&this->router, NULL);
 		if (ret != NO_ERROR)
 		{
-			DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx", ret);
+			DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx (%s)", ret, 
+				human_readable_error(buf, ret, sizeof(buf)));
 		}
 	}
 	return SUCCESS;
@@ -748,6 +960,8 @@
 	private_kernel_iph_net_t *this;
 	ULONG res;
 
+	char buf[512];
+
 	INIT(this,
 		.public = {
 			.interface = {
@@ -774,8 +988,8 @@
 								  this, TRUE, &this->changes);
 	if (res != NO_ERROR)
 	{
-		DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx",
-			 res);
+		DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx (%s)",
+			 res, human_readable_error(buf, res, sizeof(buf)));
 		destroy(this);
 		return NULL;
 	}
diff -ruN strongswan-5.8.4/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c
--- strongswan-5.8.4/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c	2022-07-08 11:03:52.756696000 +0300
@@ -19,8 +19,11 @@
 
 #include <daemon.h>
 #include <ipsec.h>
+#ifdef WIN32
+#include <networking/windows_tun.h>
+#else
 #include <networking/tun_device.h>
-
+#endif
 #define TUN_DEFAULT_MTU 1400
 
 typedef struct private_kernel_libipsec_plugin_t private_kernel_libipsec_plugin_t;
@@ -95,12 +98,23 @@
 	free(this);
 }
 
+#ifdef WIN32
+METHOD(plugin_t, reload, bool,
+	private_kernel_libipsec_plugin_t *this)
+{
+	this->router->reload(this->router);
+	return TRUE;
+}
+#endif
+
 /*
  * see header file
  */
 plugin_t *kernel_libipsec_plugin_create()
 {
 	private_kernel_libipsec_plugin_t *this;
+	char buf[512];
+	HANDLE pseudohandle = GetCurrentProcess();
 
 	if (!lib->caps->check(lib->caps, CAP_NET_ADMIN))
 	{	/* required to create TUN devices */
@@ -115,6 +129,9 @@
 				.get_name = _get_name,
 				.get_features = _get_features,
 				.destroy = _destroy,
+#ifdef WIN32
+				.reload = _reload,
+#endif
 			},
 		},
 	);
@@ -130,6 +147,17 @@
 	if (!this->tun)
 	{
 		DBG1(DBG_KNL, "failed to create TUN device");
+		if (lib->settings->get_bool(lib->settings, "%s.use_wintun", FALSE,
+					 lib->ns))
+		{
+			/** Windows is incredibly wonky and a lot of memory allocation
+			 * goes wrong is anything goes wrong in setupapi when setting up wintun
+			 * so we need to bail out here and stop the whole process.
+			 * It's pointless to try to continue because the event handler won't be
+			 * set up properly (queue will not be allocated, lock will be a NULL pointer, ...)
+			 */
+			charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL);
+		}		
 		destroy(this);
 		return NULL;
 	}
@@ -145,5 +173,14 @@
 	/* set TUN device as default to install VIPs */
 	lib->settings->set_str(lib->settings, "%s.install_virtual_ip_on",
 						   this->tun->get_name(this->tun), lib->ns);
+	
+	/* Need highest priority (not realtime for now) 
+	 * to make sure strongSwan can always process packets */
+	if(!SetPriorityClass(pseudohandle, HIGH_PRIORITY_CLASS))
+	{
+		DBG1(DBG_LIB, "Failed to raise process priority: %s", dlerror_mt(buf, sizeof(buf)));
+	} else {
+		DBG1(DBG_LIB, "Raised process priority to HIGH_PRIORITY_CLASS");
+	}	
 	return &this->public.plugin;
 }
diff -ruN strongswan-5.8.4/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c
--- strongswan-5.8.4/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c	2022-07-08 11:18:02.028706000 +0300
@@ -16,6 +16,11 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#ifdef WIN32
+#include <signal.h>
+#include <synchapi.h>
+#endif
+
 #include "kernel_libipsec_router.h"
 
 #include <daemon.h>
@@ -25,6 +30,7 @@
 #include <threading/rwlock.h>
 #include <threading/thread.h>
 #include <processing/jobs/callback_job.h>
+#include <processing/jobs/acquire_job.h>
 
 typedef struct private_kernel_libipsec_router_t private_kernel_libipsec_router_t;
 
@@ -35,7 +41,11 @@
 	/** virtual IP (points to internal data of tun) */
 	host_t *addr;
 	/** underlying TUN file descriptor (cached from tun) */
+#ifdef WIN32
+	HANDLE handle;
+#else
 	int fd;
+#endif /* !WIN32 */
 	/** TUN device */
 	tun_device_t *tun;
 } tun_entry_t;
@@ -71,10 +81,44 @@
 	 */
 	rwlock_t *lock;
 
+#ifdef WIN32
+	/**
+	 * Event we use to signal handle_plain() about changes regarding tun devices
+	 */
+	HANDLE event;
+	
+	/**
+	 * This is a notification value that we atomically set and reset if we don't use events right now.
+	 * It's used so we can avoid using WaitFor* functions when busy looping.
+	 */
+	volatile bool notify;
+	
+	/**
+	 * Setting for waiting on event or using busy loop
+	 */
+	bool use_events;
+	
+	/**
+	 * Whether a packet could be read from any of the tun devices in the last
+	 * iteration of handle_plain
+	 */
+	bool got_result;
+	
+	/**
+	 * How long the spinloop should run in microseconds after failing to
+	 * get a packet before it waits for events again.
+	 */
+	uint64_t spinloop_threshold;
+	
+	LARGE_INTEGER switching_time;
+	
+	bool windows_close;
+#else
 	/**
 	 * Pipe to signal handle_plain() about changes regarding TUN devices
 	 */
 	int notify[2];
+#endif
 };
 
 /**
@@ -102,6 +146,19 @@
 }
 
 /**
+ * Raise an acquire event
+ */
+static void raise_acquire(void *data, uint32_t reqid,
+			  traffic_selector_t *source_ts,
+			  traffic_selector_t *destination_ts)
+{
+	lib->processor->queue_job(lib->processor, (job_t *) acquire_job_create(
+		 reqid,
+		 source_ts,
+		 destination_ts));
+}
+
+/**
  * Receiver callback
  */
 static void receiver_esp_cb(void *data, packet_t *packet)
@@ -152,6 +209,25 @@
 	}
 }
 
+static bool process_plain_wintun(tun_device_t *tun)
+{
+	chunk_t raw;
+	if (tun->read_packet(tun, &raw))
+	{
+		ip_packet_t *packet;
+
+		packet = ip_packet_create(raw);
+		if (packet)
+		{
+			ipsec->processor->queue_outbound(ipsec->processor, packet);
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+#ifndef WIN32
+
 /**
  * Find flagged revents in a pollfd set by fd
  */
@@ -169,6 +245,8 @@
 	return 0;
 }
 
+#endif
+
 /**
  * Job handling outbound plaintext packets
  */
@@ -176,13 +254,13 @@
 {
 	enumerator_t *enumerator;
 	tun_entry_t *entry;
-	bool oldstate;
 	int count = 0;
+#ifndef WIN32
+	bool oldstate;
 	char buf[1];
 	struct pollfd *pfd;
 
 	this->lock->read_lock(this->lock);
-
 	pfd = alloca(sizeof(*pfd) * (this->tuns->get_count(this->tuns) + 2));
 	pfd[count].fd = this->notify[0];
 	pfd[count].events = POLLIN;
@@ -190,7 +268,6 @@
 	pfd[count].fd = this->tun.fd;
 	pfd[count].events = POLLIN;
 	count++;
-
 	enumerator = this->tuns->create_enumerator(this->tuns);
 	while (enumerator->enumerate(enumerator, NULL, &entry))
 	{
@@ -234,7 +311,180 @@
 		}
 	}
 	enumerator->destroy(enumerator);
-	this->lock->unlock(this->lock);
+#else
+	LARGE_INTEGER StartingTime = { .QuadPart = 0 },
+		EndingTime = { .QuadPart = 0 },
+		ElapsedMicroseconds = { .QuadPart = 0},
+		Frequency = { .QuadPart = 0};
+	uint64_t processed_packets = 0, failed_calls = 0;
+	
+	QueryPerformanceFrequency(&Frequency); 	
+	
+	this->lock->read_lock(this->lock);
+	if(this->use_events || !this->got_result) {
+		DBG2(DBG_LIB, "Running in event driven mode.");
+		QueryPerformanceCounter(&this->switching_time);
+		HANDLE *tun_handles;
+		DWORD ret;
+		/* Check if any of the TUN devices has data for reading */
+		tun_handles = alloca(sizeof(HANDLE)* (this->tuns->get_count(this->tuns)+2));
+		tun_handles[count] = this->event;
+		count++;
+		tun_handles[count] = this->tun.handle;
+		count++;
+		enumerator = this->tuns->create_enumerator(this->tuns);
+		while (enumerator->enumerate(enumerator, NULL, &entry))
+		{
+			tun_handles[count] = entry->handle;
+			count++;
+		}
+
+		enumerator->destroy(enumerator);
+		this->lock->unlock(this->lock);
+		QueryPerformanceCounter(&StartingTime);
+		ret = WaitForMultipleObjects(count, tun_handles, FALSE, INFINITE);
+		QueryPerformanceCounter(&EndingTime);
+		ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
+		ElapsedMicroseconds.QuadPart *= 1000000000;
+		ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
+		DBG2(DBG_LIB, "Waited for %lld nanoseconds (%lld miliseconds)", ElapsedMicroseconds.QuadPart, ElapsedMicroseconds.QuadPart/1000000);
+		this->lock->read_lock(this->lock);
+		if (ret >= WAIT_OBJECT_0 || ret <= WAIT_OBJECT_0 + count -1)
+		{
+			int offset = ret - WAIT_OBJECT_0;
+			this->got_result = TRUE;
+			switch(offset)
+			{
+				case 0:
+					DBG2(DBG_LIB, "Interrupt job from event");
+					ResetEvent(tun_handles[offset]);
+					break;
+				case 1:
+					DBG2(DBG_LIB, "got packet in event mode");
+					process_plain(this->tun.tun);
+					break;
+				default:
+					DBG2(DBG_LIB, "got packet in event mode");
+					enumerator = this->tuns->create_enumerator(this->tuns);
+					while (enumerator->enumerate(enumerator, NULL, &entry))
+					{
+						if (WaitForSingleObjectEx(entry->handle, 0, FALSE) == WAIT_OBJECT_0)
+						{
+							process_plain(entry->tun);
+						}
+					}
+					enumerator->destroy(enumerator);
+					break;
+			}
+		} else if (ret >= WAIT_ABANDONED_0 || ret <= WAIT_ABANDONED_0 + count -1)
+		{
+			int offset = ret - WAIT_ABANDONED_0;
+			this->got_result = FALSE;
+			switch(offset)
+			{
+				case 0:
+					DBG2(DBG_LIB, "Notify handle closed.");
+					break;
+				case 1:
+					DBG2(DBG_LIB, "Primary tun handle closed");
+					break;
+				default:
+					DBG2(DBG_LIB, "Other tun handle closed at offset %d", offset);
+					break;
+			}
+			return JOB_REQUEUE_NONE;
+		}
+		else if (ret == WAIT_FAILED)
+		{
+			char error_buf[512];
+			DBG1(DBG_LIB, "Failed to wait for tun devices to be ready for reading: %s",
+			dlerror_mt(error_buf, sizeof(error_buf)));
+		}
+		QueryPerformanceCounter(&this->switching_time);
+	} else {
+		/* TODO: Set realtime priority for charon-svc.exe
+		 * (otherwise Windows suspends the process after only a couple
+		 * of processes or stops waking up the process events)
+		 */
+		this->lock->read_lock(this->lock);
+		/* Check each handle individually */
+		QueryPerformanceCounter(&EndingTime);
+		ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - this->switching_time.QuadPart;
+		ElapsedMicroseconds.QuadPart *= 1000000000;
+		ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
+		DBG2(DBG_LIB, "Delay between switching is %lld nanoseconds", ElapsedMicroseconds.QuadPart);
+		do {
+			/* Because the NT kernel scheduler stops waking up the process
+			 * if we wait too often, we need to avoid calling any WaitFor* functions.
+			 * Thus we busy loop in user space until we get no result for some time */
+			this->got_result = FALSE;
+			if(process_plain_wintun(this->tun.tun))
+			{
+				this->got_result |= TRUE;
+				processed_packets++;
+			} else {
+				failed_calls++;
+			}
+			
+			ResetEvent(this->tun.handle);
+			enumerator = this->tuns->create_enumerator(this->tuns);
+			while(enumerator->enumerate(enumerator, NULL, &entry))
+			{
+				if (process_plain_wintun(entry->tun))
+				{
+					processed_packets++;
+					this->got_result |= TRUE;
+				} else {
+					failed_calls++;
+				}
+				ResetEvent(entry->handle);
+			}
+			enumerator->destroy(enumerator);
+			
+			if (!this->got_result)
+			{
+				if(!StartingTime.QuadPart) {
+					QueryPerformanceCounter(&StartingTime);
+				} else {
+					QueryPerformanceCounter(&EndingTime);
+					ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
+					ElapsedMicroseconds.QuadPart *= 1000000000;
+					ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
+				}
+				enumerator = this->tuns->create_enumerator(this->tuns);
+				while(enumerator->enumerate(enumerator, NULL, &entry))
+				{
+					ResetEvent(entry->handle);
+				}
+				enumerator->destroy(enumerator);
+				if (ElapsedMicroseconds.QuadPart >= this->spinloop_threshold)
+				{
+					DBG2(DBG_LIB, "Processed %lld packets,"
+						" failed %lld calls to read packets"
+					 " Reached threshold at %lld nanoseconds, switching"
+					 " back to events.",
+					 processed_packets,
+					 failed_calls,
+					 ElapsedMicroseconds.QuadPart);
+					ResetEvent(this->event);
+					this->notify = FALSE;
+					break;
+				}
+			}
+			if(this->notify)
+			{
+				DBG2(DBG_LIB, "Processed %lld packets, Interrupt job from bool", processed_packets);
+				ResetEvent(this->event);
+				this->notify = FALSE;
+				break;
+			}
+
+		}
+		while(TRUE);
+	}
+ 
+#endif /* WIN32 */
+	this->lock->unlock(this->lock);	
 
 	return JOB_REQUEUE_DIRECT;
 }
@@ -243,14 +493,20 @@
 	private_kernel_libipsec_router_t *this, tun_device_t *tun, bool created)
 {
 	tun_entry_t *entry, lookup;
+#ifndef WIN32
 	char buf[] = {0x01};
+#endif
 
 	this->lock->write_lock(this->lock);
 	if (created)
 	{
 		INIT(entry,
 			.addr = tun->get_address(tun, NULL),
+#ifdef WIN32
+			.handle = tun->get_handle(tun),
+#else
 			.fd = tun->get_fd(tun),
+#endif /* !WIN32 */
 			.tun = tun,
 		);
 		this->tuns->put(this->tuns, entry, entry);
@@ -262,7 +518,12 @@
 		free(entry);
 	}
 	/* notify handler thread to recreate FD set */
+#ifdef WIN32
+	SetEvent(this->event);
+	this->notify = TRUE;
+#else
 	ignore_result(write(this->notify[1], buf, sizeof(buf)));
+#endif
 	this->lock->unlock(this->lock);
 	return TRUE;
 }
@@ -297,15 +558,25 @@
 										 (ipsec_outbound_cb_t)send_esp);
 	ipsec->processor->unregister_inbound(ipsec->processor,
 										 (ipsec_inbound_cb_t)deliver_plain);
+	ipsec->processor->unregister_acquire(ipsec->processor,
+		 (ipsec_acquire_cb_t)raise_acquire);
 	charon->kernel->remove_listener(charon->kernel, &this->public.listener);
-	this->lock->destroy(this->lock);
-	this->tuns->destroy(this->tuns);
+#ifdef WIN32
+	SetEvent(this->event);
+	this->tun.tun->destroy(this->tun.tun);
+	CloseHandle(this->tun.handle);
+	CloseHandle(this->event);
+#else
 	close(this->notify[0]);
 	close(this->notify[1]);
+#endif
+	this->lock->destroy(this->lock);
+	this->tuns->destroy(this->tuns);	
 	router = NULL;
 	free(this);
 }
 
+#ifndef WIN32
 /**
  * Set O_NONBLOCK on the given socket.
  */
@@ -314,6 +585,24 @@
 	int flags = fcntl(socket, F_GETFL);
 	return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1;
 }
+#endif
+
+#ifdef WIN32
+/**
+ * See header file
+ */
+METHOD(kernel_libipsec_router_t, reload, void,
+	private_kernel_libipsec_router_t *this)
+{
+	this->use_events = lib->settings->get_bool(
+		lib->settings, "%s.use_events", FALSE, lib->ns);
+	this->spinloop_threshold = lib->settings->get_int(
+		lib->settings, "%s.spinloop_threshold", 4000000, lib->ns);
+	DBG1(DBG_LIB, "Read new use_events setting %d and spinloop_threshold %lld",
+	this->use_events, this->spinloop_threshold);
+}
+
+#endif
 
 /*
  * See header file
@@ -329,12 +618,25 @@
 			},
 			.get_tun_name = _get_tun_name,
 			.destroy = _destroy,
+			.reload = _reload,
 		},
 		.tun = {
 			.tun = lib->get(lib, "kernel-libipsec-tun"),
-		}
+		},
+#ifdef WIN32
+		.notify = FALSE,
+#endif
 	);
-
+	this->public.reload(&this->public);
+#ifdef WIN32
+	this->tun.handle = this->tun.tun->get_handle(this->tun.tun);
+        if (!(this->event = CreateEvent(NULL, FALSE, FALSE, FALSE)))
+        {
+            DBG1(DBG_KNL, "creating notify event for kernel-libipsec router failed");
+            free(this);
+            return NULL;
+        }
+#else
 	if (pipe(this->notify) != 0 ||
 		!set_nonblock(this->notify[0]) || !set_nonblock(this->notify[1]))
 	{
@@ -345,6 +647,7 @@
 
 	this->tun.fd = this->tun.tun->get_fd(this->tun.tun);
 
+#endif /* !WIN32 */
 	this->tuns = hashtable_create((hashtable_hash_t)tun_entry_hash,
 								  (hashtable_equals_t)tun_entry_equals, 4);
 	this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
@@ -353,6 +656,7 @@
 	ipsec->processor->register_outbound(ipsec->processor, send_esp, NULL);
 	ipsec->processor->register_inbound(ipsec->processor,
 									(ipsec_inbound_cb_t)deliver_plain, this);
+	ipsec->processor->register_acquire(ipsec->processor, raise_acquire, NULL);
 	charon->receiver->add_esp_cb(charon->receiver,
 									(receiver_esp_cb_t)receiver_esp_cb, NULL);
 	lib->processor->queue_job(lib->processor,
diff -ruN strongswan-5.8.4/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.h strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.h
--- strongswan-5.8.4/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.h	2022-07-08 11:18:46.529662000 +0300
@@ -48,6 +48,14 @@
 	 * Destroy the given instance
 	 */
 	void (*destroy)(kernel_libipsec_router_t *this);
+
+#ifdef WIN32   
+   /**
+    * Reload the configuration of the router 
+    */
+   void (*reload)(kernel_libipsec_router_t *this);
+#endif
+
 };
 
 /**
diff -ruN strongswan-5.8.4/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
--- strongswan-5.8.4/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c	2022-07-06 15:47:33.870969000 +0300
@@ -228,6 +228,16 @@
 /*	{ENCR_CAMELLIA_CCM_ICV12,	"***"				}, */
 /*	{ENCR_CAMELLIA_CCM_ICV16,	"***"				}, */
 	{ENCR_SERPENT_CBC,			"serpent"			},
+	{ENCR_GOST28147_CTR_LEGACY,	"ctr(gost)"			},
+	{ENCR_GOST28147_CFB_LEGACY,	"cfb(gost)"			},
+	{ENCR_BELT_CBC_LEGACY,		"cbc(belt)"			},
+	{ENCR_BELT_CFB_LEGACY,		"cfb(belt)"			},
+	{ENCR_BELT_CTR_LEGACY,		"ctr(belt)"			},
+	{ENCR_GOST28147_CTR,		"ctr(gost)"			},
+	{ENCR_GOST28147_CFB,		"cfb(gost)"			},
+	{ENCR_BELT_CBC,				"cbc(belt)"			},
+	{ENCR_BELT_CFB,				"cfb(belt)"			},
+	{ENCR_BELT_CTR,				"ctr(belt)"			},
 	{ENCR_TWOFISH_CBC,			"twofish"			},
 	{ENCR_CHACHA20_POLY1305,	"rfc7539esp(chacha20,poly1305)"},
 };
@@ -247,6 +257,14 @@
 /*	{AUTH_DES_MAC,				"***"				}, */
 /*	{AUTH_KPDK_MD5,				"***"				}, */
 	{AUTH_AES_XCBC_96,			"xcbc(aes)"			},
+	{AUTH_BELT_HASH_LEGACY,		"belt_hash"			},
+	{AUTH_GOST_MAC_LEGACY,		"gost_mac"			},
+	{AUTH_BELT_MAC_LEGACY,		"belt_mac"			},
+	{AUTH_BELT_HMAC_LEGACY,		"belt_hmac"			},
+	{AUTH_BELT_HASH,			"belt_hash"			},
+	{AUTH_GOST_MAC,			 	"gost_mac"			},
+	{AUTH_BELT_MAC,			 	"belt_mac"			},
+	{AUTH_BELT_HMAC,		 	"belt_hmac"			},
 	{AUTH_AES_CMAC_96,			"cmac(aes)"			},
 };
 
Двоичные файлы strongswan-5.8.4/src/libcharon/plugins/kernel_wfp/ipsecdump.exe и strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_wfp/ipsecdump.exe различаются
diff -ruN strongswan-5.8.4/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c
--- strongswan-5.8.4/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c	2016-04-22 23:01:35.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c	2020-11-30 16:52:55.000000000 +0300
@@ -15,118 +15,6 @@
 
 #include <library.h>
 
-const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS = {
-	0xb235ae9a, 0x1d64, 0x49b8, { 0xa4,0x4c,0x5f,0xf3,0xd9,0x09,0x50,0x45 }
-};
-const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS = {
-	0xd9ee00de, 0xc1ef, 0x4617, { 0xbf,0xe3,0xff,0xd8,0xf5,0xa0,0x89,0x57 }
-};
-const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS = {
-	0xae96897e, 0x2e94, 0x4bc9, { 0xb3,0x13,0xb2,0x7e,0xe8,0x0e,0x57,0x4d }
-};
-const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS = {
-	0x2d79133b, 0xb390, 0x45c6, { 0x86,0x99,0xac,0xac,0xea,0xaf,0xed,0x33 }
-};
-const GUID FWPM_CONDITION_IP_LOCAL_PORT = {
-	0x0c1ba1af, 0x5765, 0x453f, { 0xaf,0x22,0xa8,0xf7,0x91,0xac,0x77,0x5b }
-};
-const GUID FWPM_CONDITION_IP_REMOTE_PORT = {
-	0xc35a604d, 0xd22b, 0x4e1a, { 0x91,0xb4,0x68,0xf6,0x74,0xee,0x67,0x4b }
-};
-const GUID FWPM_CONDITION_IP_PROTOCOL = {
-	0x3971ef2b, 0x623e, 0x4f9a, { 0x8c,0xb1,0x6e,0x79,0xb8,0x06,0xb9,0xa7 }
-};
-const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4 = {
-	0x5926dfc8, 0xe3cf, 0x4426, { 0xa2,0x83,0xdc,0x39,0x3f,0x5d,0x0f,0x9d }
-};
-const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6 = {
-	0x634a869f, 0xfc23, 0x4b90, { 0xb0,0xc1,0xbf,0x62,0x0a,0x36,0xae,0x6f }
-};
-const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4 = {
-	0x09e61aea, 0xd214, 0x46e2, { 0x9b,0x21,0xb2,0x6b,0x0b,0x2f,0x28,0xc8 }
-};
-const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6 = {
-	0xe1735bde, 0x013f, 0x4655, { 0xb3,0x51,0xa4,0x9e,0x15,0x76,0x2d,0xf0 }
-};
-const GUID FWPM_LAYER_IPFORWARD_V4 = {
-	0xa82acc24, 0x4ee1, 0x4ee1, { 0xb4,0x65,0xfd,0x1d,0x25,0xcb,0x10,0xa4}
-};
-const GUID FWPM_LAYER_IPFORWARD_V6 = {
-	0x7b964818, 0x19c7, 0x493a, { 0xb7,0x1f,0x83,0x2c,0x36,0x84,0xd2,0x8c }
-};
-const GUID FWPM_LAYER_ALE_AUTH_CONNECT_V4 = {
-	0xc38d57d1, 0x05a7, 0x4c33, { 0x90,0x4f,0x7f,0xbc,0xee,0xe6,0x0e,0x82 }
-};
-const GUID FWPM_LAYER_ALE_AUTH_CONNECT_V6 = {
-	0x4a72393b, 0x319f, 0x44bc, { 0x84,0xc3,0xba,0x54,0xdc,0xb3,0xb6,0xb4 }
-};
-const GUID FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 = {
-	0xe1cd9fe7, 0xf4b5, 0x4273, { 0x96,0xc0,0x59,0x2e,0x48,0x7b,0x86,0x50 }
-};
-const GUID FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 = {
-	0xa3b42c97, 0x9f04, 0x4672, { 0xb8,0x7e,0xce,0xe9,0xc4,0x83,0x25,0x7f }
-};
-const GUID FWPM_SUBLAYER_IPSEC_TUNNEL = {
-	0x83f299ed, 0x9ff4, 0x4967, { 0xaf,0xf4,0xc3,0x09,0xf4,0xda,0xb8,0x27 }
-};
-const GUID FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL = {
-	0xa5082e73, 0x8f71, 0x4559, { 0x8a,0x9a,0x10,0x1c,0xea,0x04,0xef,0x87 }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 = {
-	0x5132900d, 0x5e84, 0x4b5f, { 0x80,0xe4,0x01,0x74,0x1e,0x81,0xff,0x10 }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6 = {
-	0x49d3ac92, 0x2a6c, 0x4dcf, { 0x95,0x5f,0x1c,0x3b,0xe0,0x09,0xdd,0x99 }
-};
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 = {
-	0x4b46bf0a, 0x4523, 0x4e57, { 0xaa,0x38,0xa8,0x79,0x87,0xc9,0x10,0xd9 }
-};
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6 = {
-	0x38d87722, 0xad83, 0x4f11, { 0xa9,0x1f,0xdf,0x0f,0xb0,0x77,0x22,0x5b }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4 = {
-	0x191a8a46, 0x0bf8, 0x46cf, { 0xb0,0x45,0x4b,0x45,0xdf,0xa6,0xa3,0x24 }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6 = {
-	0x80c342e3, 0x1e53, 0x4d6f, { 0x9b,0x44,0x03,0xdf,0x5a,0xee,0xe1,0x54 }
-};
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 = {
-	0x70a4196c, 0x835b, 0x4fb0, { 0x98,0xe8,0x07,0x5f,0x4d,0x97,0x7d,0x46 }
-};
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 = {
-	0xf1835363, 0xa6a5, 0x4e62, { 0xb1,0x80,0x23,0xdb,0x78,0x9d,0x8d,0xa6 }
-};
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 = {
-	0x28829633, 0xc4f0, 0x4e66, { 0x87,0x3f,0x84,0x4d,0xb2,0xa8,0x99,0xc7 }
-};
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 = {
-	0xaf50bec2, 0xc686, 0x429a, { 0x88,0x4d,0xb7,0x44,0x43,0xe7,0xb0,0xb4 }
-};
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 = {
-	0xfb532136, 0x15cb, 0x440b, { 0x93,0x7c,0x17,0x17,0xca,0x32,0x0c,0x40 }
-};
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 = {
-	0xdae640cc, 0xe021, 0x4bee, { 0x9e,0xb6,0xa4,0x8b,0x27,0x5c,0x8c,0x1d }
-};
-const GUID FWPM_CALLOUT_IPSEC_ALE_CONNECT_V4 = {
-	0x6ac141fc, 0xf75d, 0x4203, { 0xb9,0xc8,0x48,0xe6,0x14,0x9c,0x27,0x12 }
-};
-const GUID FWPM_CALLOUT_IPSEC_ALE_CONNECT_V6 = {
-	0x4c0dda05, 0xe31f, 0x4666, { 0x90,0xb0,0xb3,0xdf,0xad,0x34,0x12,0x9a  }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V4 = {
-	0x3df6e7de, 0xfd20, 0x48f2, { 0x9f,0x26,0xf8,0x54,0x44,0x4c,0xba,0x79 }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V6 = {
-	0xa1e392d3, 0x72ac, 0x47bb, { 0x87,0xa7,0x01,0x22,0xc6,0x94,0x34,0xab }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V4 = {
-	0x7dff309b, 0xba7d, 0x4aba, { 0x91,0xaa,0xae,0x5c,0x66,0x40,0xc9,0x44 }
-};
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V6 = {
-	0xa9a0d6d9, 0xc58c, 0x474e, { 0x8a,0xeb,0x3c,0xfe,0x99,0xd6,0xd5,0x3d }
-};
-
 /**
  * Load a function symbol from a loaded dll
  */
diff -ruN strongswan-5.8.4/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h
--- strongswan-5.8.4/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h	2016-04-22 23:01:35.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h	2020-11-30 16:52:55.000000000 +0300
@@ -107,50 +107,124 @@
 	IPSEC_SA_BUNDLE_FLAG_FORWARD_PATH_INITIATOR =				(1<<17),
 };
 
-/* missing in some MinGW versions */
-const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS;
-const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS;
-const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS;
-const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS;
-const GUID FWPM_CONDITION_IP_LOCAL_PORT;
-const GUID FWPM_CONDITION_IP_REMOTE_PORT;
-const GUID FWPM_CONDITION_IP_PROTOCOL;
 #ifndef FWPM_CONDITION_ICMP_TYPE
 # define FWPM_CONDITION_ICMP_TYPE FWPM_CONDITION_IP_LOCAL_PORT
 #endif
 #ifndef FWPM_CONDITION_ICMP_CODE
 # define FWPM_CONDITION_ICMP_CODE FWPM_CONDITION_IP_REMOTE_PORT
 #endif
-const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4;
-const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6;
-const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
-const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6;
-const GUID FWPM_LAYER_IPFORWARD_V4;
-const GUID FWPM_LAYER_IPFORWARD_V6;
-const GUID FWPM_LAYER_ALE_AUTH_CONNECT_V4;
-const GUID FWPM_LAYER_ALE_AUTH_CONNECT_V6;
-const GUID FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
-const GUID FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
-const GUID FWPM_SUBLAYER_IPSEC_TUNNEL;
-const GUID FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6;
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4;
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6;
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4;
-const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6;
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4;
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6;
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4;
-const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6;
-const GUID FWPM_CALLOUT_IPSEC_ALE_CONNECT_V4;
-const GUID FWPM_CALLOUT_IPSEC_ALE_CONNECT_V6;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V4;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V6;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V4;
-const GUID FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V6;
+
+const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS = {
+	0xb235ae9a, 0x1d64, 0x49b8, { 0xa4,0x4c,0x5f,0xf3,0xd9,0x09,0x50,0x45 }
+};
+const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS = {
+	0xd9ee00de, 0xc1ef, 0x4617, { 0xbf,0xe3,0xff,0xd8,0xf5,0xa0,0x89,0x57 }
+};
+const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS = {
+	0xae96897e, 0x2e94, 0x4bc9, { 0xb3,0x13,0xb2,0x7e,0xe8,0x0e,0x57,0x4d }
+};
+const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS = {
+	0x2d79133b, 0xb390, 0x45c6, { 0x86,0x99,0xac,0xac,0xea,0xaf,0xed,0x33 }
+};
+const GUID FWPM_CONDITION_IP_LOCAL_PORT = {
+	0x0c1ba1af, 0x5765, 0x453f, { 0xaf,0x22,0xa8,0xf7,0x91,0xac,0x77,0x5b }
+};
+const GUID FWPM_CONDITION_IP_REMOTE_PORT = {
+	0xc35a604d, 0xd22b, 0x4e1a, { 0x91,0xb4,0x68,0xf6,0x74,0xee,0x67,0x4b }
+};
+const GUID FWPM_CONDITION_IP_PROTOCOL = {
+	0x3971ef2b, 0x623e, 0x4f9a, { 0x8c,0xb1,0x6e,0x79,0xb8,0x06,0xb9,0xa7 }
+};
+const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4 = {
+	0x5926dfc8, 0xe3cf, 0x4426, { 0xa2,0x83,0xdc,0x39,0x3f,0x5d,0x0f,0x9d }
+};
+const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6 = {
+	0x634a869f, 0xfc23, 0x4b90, { 0xb0,0xc1,0xbf,0x62,0x0a,0x36,0xae,0x6f }
+};
+const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4 = {
+	0x09e61aea, 0xd214, 0x46e2, { 0x9b,0x21,0xb2,0x6b,0x0b,0x2f,0x28,0xc8 }
+};
+const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6 = {
+	0xe1735bde, 0x013f, 0x4655, { 0xb3,0x51,0xa4,0x9e,0x15,0x76,0x2d,0xf0 }
+};
+const GUID FWPM_LAYER_IPFORWARD_V4 = {
+	0xa82acc24, 0x4ee1, 0x4ee1, { 0xb4,0x65,0xfd,0x1d,0x25,0xcb,0x10,0xa4}
+};
+const GUID FWPM_LAYER_IPFORWARD_V6 = {
+	0x7b964818, 0x19c7, 0x493a, { 0xb7,0x1f,0x83,0x2c,0x36,0x84,0xd2,0x8c }
+};
+const GUID FWPM_LAYER_ALE_AUTH_CONNECT_V4 = {
+	0xc38d57d1, 0x05a7, 0x4c33, { 0x90,0x4f,0x7f,0xbc,0xee,0xe6,0x0e,0x82 }
+};
+const GUID FWPM_LAYER_ALE_AUTH_CONNECT_V6 = {
+	0x4a72393b, 0x319f, 0x44bc, { 0x84,0xc3,0xba,0x54,0xdc,0xb3,0xb6,0xb4 }
+};
+const GUID FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 = {
+	0xe1cd9fe7, 0xf4b5, 0x4273, { 0x96,0xc0,0x59,0x2e,0x48,0x7b,0x86,0x50 }
+};
+const GUID FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 = {
+	0xa3b42c97, 0x9f04, 0x4672, { 0xb8,0x7e,0xce,0xe9,0xc4,0x83,0x25,0x7f }
+};
+const GUID FWPM_SUBLAYER_IPSEC_TUNNEL = {
+	0x83f299ed, 0x9ff4, 0x4967, { 0xaf,0xf4,0xc3,0x09,0xf4,0xda,0xb8,0x27 }
+};
+const GUID FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL = {
+	0xa5082e73, 0x8f71, 0x4559, { 0x8a,0x9a,0x10,0x1c,0xea,0x04,0xef,0x87 }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 = {
+	0x5132900d, 0x5e84, 0x4b5f, { 0x80,0xe4,0x01,0x74,0x1e,0x81,0xff,0x10 }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6 = {
+	0x49d3ac92, 0x2a6c, 0x4dcf, { 0x95,0x5f,0x1c,0x3b,0xe0,0x09,0xdd,0x99 }
+};
+const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 = {
+	0x4b46bf0a, 0x4523, 0x4e57, { 0xaa,0x38,0xa8,0x79,0x87,0xc9,0x10,0xd9 }
+};
+const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6 = {
+	0x38d87722, 0xad83, 0x4f11, { 0xa9,0x1f,0xdf,0x0f,0xb0,0x77,0x22,0x5b }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4 = {
+	0x191a8a46, 0x0bf8, 0x46cf, { 0xb0,0x45,0x4b,0x45,0xdf,0xa6,0xa3,0x24 }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6 = {
+	0x80c342e3, 0x1e53, 0x4d6f, { 0x9b,0x44,0x03,0xdf,0x5a,0xee,0xe1,0x54 }
+};
+const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 = {
+	0x70a4196c, 0x835b, 0x4fb0, { 0x98,0xe8,0x07,0x5f,0x4d,0x97,0x7d,0x46 }
+};
+const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 = {
+	0xf1835363, 0xa6a5, 0x4e62, { 0xb1,0x80,0x23,0xdb,0x78,0x9d,0x8d,0xa6 }
+};
+const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 = {
+	0x28829633, 0xc4f0, 0x4e66, { 0x87,0x3f,0x84,0x4d,0xb2,0xa8,0x99,0xc7 }
+};
+const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 = {
+	0xaf50bec2, 0xc686, 0x429a, { 0x88,0x4d,0xb7,0x44,0x43,0xe7,0xb0,0xb4 }
+};
+const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 = {
+	0xfb532136, 0x15cb, 0x440b, { 0x93,0x7c,0x17,0x17,0xca,0x32,0x0c,0x40 }
+};
+const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 = {
+	0xdae640cc, 0xe021, 0x4bee, { 0x9e,0xb6,0xa4,0x8b,0x27,0x5c,0x8c,0x1d }
+};
+const GUID FWPM_CALLOUT_IPSEC_ALE_CONNECT_V4 = {
+	0x6ac141fc, 0xf75d, 0x4203, { 0xb9,0xc8,0x48,0xe6,0x14,0x9c,0x27,0x12 }
+};
+const GUID FWPM_CALLOUT_IPSEC_ALE_CONNECT_V6 = {
+	0x4c0dda05, 0xe31f, 0x4666, { 0x90,0xb0,0xb3,0xdf,0xad,0x34,0x12,0x9a  }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V4 = {
+	0x3df6e7de, 0xfd20, 0x48f2, { 0x9f,0x26,0xf8,0x54,0x44,0x4c,0xba,0x79 }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V6 = {
+	0xa1e392d3, 0x72ac, 0x47bb, { 0x87,0xa7,0x01,0x22,0xc6,0x94,0x34,0xab }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V4 = {
+	0x7dff309b, 0xba7d, 0x4aba, { 0x91,0xaa,0xae,0x5c,0x66,0x40,0xc9,0x44 }
+};
+const GUID FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V6 = {
+	0xa9a0d6d9, 0xc58c, 0x474e, { 0x8a,0xeb,0x3c,0xfe,0x99,0xd6,0xd5,0x3d }
+};
 
 /* integrity config, missing in some MinGW versions */
 #ifndef IPSEC_AUTH_CONFIG_HMAC_MD5_96
diff -ruN strongswan-5.8.4/src/libcharon/plugins/stroke/stroke_cred.c strongswancont-5.8.4-svc/src/libcharon/plugins/stroke/stroke_cred.c
--- strongswan-5.8.4/src/libcharon/plugins/stroke/stroke_cred.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/stroke/stroke_cred.c	2022-07-06 15:47:33.894969000 +0300
@@ -1043,29 +1043,91 @@
 	return TRUE;
 }
 
+static bool load_from_usbbar(chunk_t line, int line_nr, char *path, 
+												private_key_t **result)
+{
+	/*get protected password filename*/
+	chunk_t filename;
+
+	err_t ugh = extract_value(&filename, &line);
+
+	if (ugh != NULL)
+	{
+		DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
+		return FALSE;
+	}
+	if (filename.len == 0)
+	{
+		DBG1(DBG_CFG, "line %d: empty filename", line_nr);
+		return FALSE;
+	}
+
+	snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
+
+	*result = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+		KEY_ANY, BUILD_USBBAR_PASS, path, BUILD_END);
+
+	return TRUE;
+}
+
+static bool load_from_bpki(chunk_t line, int line_nr,
+							private_key_t **result)
+{
+	if (line.len == 0)
+	{
+		DBG1(DBG_CFG, "line %d: empty params", line_nr);
+		return FALSE;
+	}
+
+	*result = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+		KEY_BIGN, BUILD_BPKI_PARAMS, line, BUILD_END);
+
+	return TRUE;
+}
+
 /**
  * Load a private key
  */
 static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
 						 FILE *prompt, key_type_t key_type)
 {
-	char path[PATH_MAX];
-	private_key_t *key;
+	char path[PATH_MAX], key_from[1024] = {0,};
+	private_key_t *key = NULL;
 
-	if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
+	if(key_type == KEY_BIGN) 
+	{
+		strcpy(key_from, "BPKI Containers");
+		if(!load_from_bpki(line, line_nr, &key))
+		{
+			return FALSE;
+		}
+	}
+	else if(key_type != KEY_ANY) 
+	{
+		if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
 						key_type, (void**)&key))
+		{
+			return FALSE;
+		}
+		strcpy(key_from, path);
+	}
+	else 
 	{
-		return FALSE;
+		strcpy(key_from, "USB-Barrier");
+		if(!load_from_usbbar(line, line_nr, path, &key))
+		{
+			return FALSE;			
+		}
 	}
 	if (key)
 	{
 		DBG1(DBG_CFG, "  loaded %N private key from '%s'",
-			 key_type_names, key->get_type(key), path);
+			 key_type_names, key->get_type(key), key_from);
 		secrets->add_key(secrets, key);
 	}
 	else
 	{
-		DBG1(DBG_CFG, "  loading private key from '%s' failed", path);
+		DBG1(DBG_CFG, "  loading private key from '%s' failed", key_from);
 	}
 	return TRUE;
 }
@@ -1347,10 +1409,27 @@
 				break;
 			}
 		}
+		/* USB-Barrier private key storage support: */
+		else if (match("USBBAR", &token))
+		{
+			if(!load_private(secrets, line, line_nr, prompt, KEY_ANY))
+			{
+				break;
+			}
+		}
+		/* BPKI: */
+		else if (match("BPKI", &token))
+		{
+			if(!load_private(secrets, line, line_nr, prompt, KEY_BIGN))
+			{
+				break;
+			}
+		}
 		else
 		{
 			DBG1(DBG_CFG, "line %d: token must be either RSA, ECDSA, BLISS, "
-						  "PKCS8 P12, PIN, PSK, EAP, XAUTH or NTLM", line_nr);
+						  "PKCS8 P12, PIN, PSK, EAP, XAUTH, NTLM, "
+						  "USBBAR or BPKI", line_nr);
 			break;
 		}
 	}
diff -ruN strongswan-5.8.4/src/libcharon/plugins/stroke/stroke_list.c strongswancont-5.8.4-svc/src/libcharon/plugins/stroke/stroke_list.c
--- strongswan-5.8.4/src/libcharon/plugins/stroke/stroke_list.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/stroke/stroke_list.c	2022-07-06 15:47:33.906969000 +0300
@@ -752,7 +752,18 @@
 	{
 		return FALSE;
 	}
-	if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))
+
+	if(public->get_type(public) == KEY_BIGN)
+	{
+		if (public->get_fingerprint(public, KEYID_PUBKEY_BELT, &keyid))
+		{
+			id = identification_create_from_encoding(ID_KEY_ID, keyid);
+			private = lib->credmgr->get_private(lib->credmgr,
+										public->get_type(public), id, NULL);
+			id->destroy(id);
+		}
+	}
+	else if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid))	
 	{
 		id = identification_create_from_encoding(ID_KEY_ID, keyid);
 		private = lib->credmgr->get_private(lib->credmgr,
diff -ruN strongswan-5.8.4/src/libcharon/plugins/vici/vici_config.c strongswancont-5.8.4-svc/src/libcharon/plugins/vici/vici_config.c
--- strongswan-5.8.4/src/libcharon/plugins/vici/vici_config.c	2019-12-17 01:04:51.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/vici/vici_config.c	2023-05-13 16:25:54.224946000 +0300
@@ -335,6 +335,9 @@
 	char *mediated_by;
 	identification_t *peer_id;
 #endif /* ME */
+#ifdef _WIN32
+	bool block_dns;
+#endif /* _WIN32 */
 } peer_data_t;
 
 /**
@@ -445,6 +448,9 @@
 		DBG2(DBG_CFG, "  mediation_peer = %Y", data->peer_id);
 	}
 #endif /* ME */
+#ifdef _WIN32
+	DBG2(DBG_CFG, "  block_dns = %u", data->block_dns);
+#endif /* _WIN32 */
 
 	if (data->vips->get_count(data->vips))
 	{
@@ -1834,6 +1840,9 @@
 		{ "mediated_by",	parse_string,		&peer->mediated_by			},
 		{ "mediation_peer",	parse_peer_id,		&peer->peer_id				},
 #endif /* ME */
+#ifdef _WIN32
+		{ "block_dns",		parse_bool,			&peer->block_dns			},		
+#endif /* _WIN32 */
 	};
 
 	return parse_rules(rules, countof(rules), name, value,
@@ -2559,6 +2568,9 @@
 		.fragmentation = peer.fragmentation,
 		.childless = peer.childless,
 		.dscp = peer.dscp,
+#ifdef _WIN32
+		.block_dns = peer.block_dns,
+#endif /* _WIN32 */
 	};
 	ike_cfg = ike_cfg_create(&ike);
 
diff -ruN strongswan-5.8.4/src/libcharon/plugins/vici/vici_cred.c strongswancont-5.8.4-svc/src/libcharon/plugins/vici/vici_cred.c
--- strongswan-5.8.4/src/libcharon/plugins/vici/vici_cred.c	2018-10-23 20:03:28.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/vici/vici_cred.c	2023-04-30 14:50:33.174009000 +0300
@@ -172,6 +172,7 @@
 							  BUILD_BLOB_PEM, data,
 							  BUILD_X509_FLAG, ext_flag,
 							  BUILD_END);
+
 	if (!cert)
 	{
 		return create_reply("parsing %N certificate failed",
@@ -212,38 +213,83 @@
 	chunk_t data, fp;
 	char *str;
 
+	char params[2048] = {0};
+	char key_name[256] = {0};
+	char path[1024] = {0};
+	char pwd[256] = {0};
+
 	str = message->get_str(message, NULL, "type");
 	if (!str)
 	{
 		return create_reply("key type missing");
 	}
-	if (strcaseeq(str, "any"))
+	if (strcaseeq(str, "bign"))
 	{
-		type = KEY_ANY;
-	}
-	else if (strcaseeq(str, "rsa"))
-	{
-		type = KEY_RSA;
-	}
-	else if (strcaseeq(str, "ecdsa"))
-	{
-		type = KEY_ECDSA;
-	}
-	else if (strcaseeq(str, "bliss"))
-	{
-		type = KEY_BLISS;
+		type = KEY_BIGN;
+
+		str = message->get_str(message, NULL, "name");
+		if (!str)
+		{
+			return create_reply("bign key name missing");
+		}
+		data = chunk_from_hex(chunk_from_str(str), NULL);
+		memcpy(key_name, data.ptr, data.len);
+
+		str = message->get_str(message, NULL, "file");
+		if (!str)
+		{
+			return create_reply("second share key file path missing");
+		}
+		data = chunk_from_hex(chunk_from_str(str), NULL);
+		memcpy(path, data.ptr, data.len);
+
+		str = message->get_str(message, NULL, "pwd");
+		if (!str)
+		{
+			return create_reply("password missing");
+		}
+		data = chunk_from_hex(chunk_from_str(str), NULL);
+		memcpy(pwd, data.ptr, data.len);
+
+		sprintf(params, "PRIV_KEY=\"swanctl\\bpki\\PrivKey_%s.pkc\" PWD=\"%s\" SHARE_SECR1=\"swanctl\\bpki\\ShareKey1_%s.ssc\" SHARE_SECR2=\"%s\"",
+			    key_name, pwd, key_name, path);
+
+		memset(pwd, 0, 256);
+
+		key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+								 BUILD_BPKI_PARAMS, chunk_from_str(params),
+								 BUILD_END);
 	}
 	else
 	{
-		return create_reply("invalid key type: %s", str);
-	}
-	data = message->get_value(message, chunk_empty, "data");
-	if (!data.len)
-	{
-		return create_reply("key data missing");
-	}
-	key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
-							 BUILD_BLOB_PEM, data, BUILD_END);
+		if (strcaseeq(str, "any"))
+		{
+			type = KEY_ANY;
+		}
+		else if (strcaseeq(str, "rsa"))
+		{
+			type = KEY_RSA;
+		}
+		else if (strcaseeq(str, "ecdsa"))
+		{
+			type = KEY_ECDSA;
+		}
+		else if (strcaseeq(str, "bliss"))
+		{
+			type = KEY_BLISS;
+		}
+		else
+		{
+			return create_reply("invalid key type: %s", str);
+		}
+		data = message->get_value(message, chunk_empty, "data");
+		if (!data.len)
+		{
+			return create_reply("key data missing");
+		}
+		key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+								 BUILD_BLOB_PEM, data, BUILD_END);
+	}	
 	if (!key)
 	{
 		return create_reply("parsing %N private key failed",
diff -ruN strongswan-5.8.4/src/libcharon/plugins/vici/vici_query.c strongswancont-5.8.4-svc/src/libcharon/plugins/vici/vici_query.c
--- strongswan-5.8.4/src/libcharon/plugins/vici/vici_query.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/plugins/vici/vici_query.c	2023-06-15 15:57:18.846786000 +0300
@@ -51,12 +51,14 @@
 #ifdef HAVE_MALLINFO
 #include <malloc.h>
 #endif
+#include "locale.h"
 
 #include <daemon.h>
 #include <asn1/asn1.h>
 #include <credentials/certificates/certificate.h>
 #include <credentials/certificates/x509.h>
 #include <counters_query.h>
+#include <plugins/contactcrypto/contactcrypto_private_key.h>
 
 ENUM(vici_counter_type_names,
 	COUNTER_INIT_IKE_SA_REKEY, COUNTER_OUT_INFORMATIONAL_RSP,
@@ -112,6 +114,25 @@
 };
 
 /**
+ * Create a (error) reply message
+ */
+static vici_message_t* create_reply(char *fmt, ...)
+{
+	vici_builder_t *builder;
+	va_list args;
+
+	builder = vici_builder_create();
+	builder->add_kv(builder, "success", fmt ? "no" : "yes");
+	if (fmt)
+	{
+		va_start(args, fmt);
+		builder->vadd_kv(builder, "errmsg", fmt, args);
+		va_end(args);
+	}
+	return builder->finalize(builder);
+}
+
+/**
  * Add the given mark/mask to the message using the provided labels
  */
 static void add_mark(vici_builder_t *b, mark_t mark,
@@ -1057,7 +1078,9 @@
 	while (enumerator->enumerate(enumerator, &cert))
 	{
 		x509 = (x509_t*)cert;
-		if ((x509->get_flags(x509) & X509_ANY) != flag)
+
+		if (((x509->get_flags(x509) & X509_ANY) != flag) &&
+			!(x509->get_flags(x509) & flag) )
 		{
 			continue;
 		}
@@ -1665,6 +1688,597 @@
 	return b->finalize(b);
 }
 
+FILE* ext_fopen(const char*filename, const char*mode)
+{
+#ifdef _WIN32
+	int new_Len1 = 0;
+	int new_Len2 = 0;
+	int fn_len_s = strlen(filename);
+	int m_len_s  = strlen(mode);
+	if(fn_len_s==0) 
+		return NULL;
+	if(m_len_s==0)
+		return NULL;
+	wchar_t path[MAX_PATH];
+	wchar_t wmode[MAX_PATH];
+	new_Len1 = MultiByteToWideChar(CP_UTF8, 0, filename, fn_len_s, path, fn_len_s);
+	if(new_Len1>=MAX_PATH) return NULL;
+	path[new_Len1] = L'\0';
+	new_Len2 = MultiByteToWideChar(CP_UTF8, 0, mode, m_len_s, wmode, m_len_s);
+	if(new_Len2>=MAX_PATH) return NULL;
+	wmode[new_Len2] = L'\0';
+	return _wfopen(path, wmode);
+#else
+	return fopen(filename, mode);
+#endif
+}
+
+int ext_remove(const char*filename)
+{
+#ifdef _WIN32
+	int new_Len = 0;
+	int fn_len_s = strlen(filename);
+	if(fn_len_s==0) 
+		return NULL;
+	wchar_t path[MAX_PATH];
+	new_Len = MultiByteToWideChar(CP_UTF8, 0, filename, fn_len_s, path, fn_len_s);
+	if(new_Len>=MAX_PATH) return NULL;
+	path[new_Len] = L'\0';    
+	return _wremove(path);
+#else
+	return remove(filename);
+#endif
+}
+
+CALLBACK(build_certreq, vici_message_t*,
+	private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
+{
+	chunk_t data, pass = chunk_empty, random = chunk_empty,
+			hash_init_data = chunk_empty, hekey_chunk = chunk_empty,
+			init_data = chunk_empty, certreq_chunk = chunk_empty,
+			privkey_chunk = chunk_empty, sharekey1_chunk = chunk_empty,
+			sharekey2_chunk = chunk_empty;
+	int validity;
+	bool add_gov_pki, use_78_ext_req;
+	char errmsg[1024], dn[4096] = {0}, key_name[256] = {0}, *temp,
+			out_file_certreq[1024] = {0}, out_file_privkey[1024] = {0},
+			out_file_sharekey1[1024] = {0}, out_file_sharekey2[1024]  = {0};
+	signature_params_t *scheme = NULL;
+	private_key_t *subj_private = NULL;
+	identification_t *subj_id = NULL;
+	certificate_t *subj_cert = NULL;
+	linked_list_t *san = linked_list_create();
+	identification_t *san_value = NULL;
+	shared_key_t *user_pwd = NULL, *high_entropy_key = NULL;
+	rng_t *rng = NULL;
+	prf_t *prf = NULL;
+	hasher_t *hasher = NULL;
+	uint8_t seed[32];
+	FILE *f;
+
+	memset(errmsg, 0, 1024);
+
+	// keyname
+	temp = request->get_str(request, NULL, "keyname");
+	if (!temp)
+	{
+		strcpy(errmsg, "key name missing");
+		goto end;
+	}
+	data = chunk_from_hex(chunk_from_str(temp), NULL);
+	memcpy(key_name, data.ptr, data.len);
+	chunk_free(&data);
+
+	sprintf(out_file_privkey, "swanctl\\bpki\\PrivKey_%s.pkc", key_name);
+	f = ext_fopen(out_file_privkey, "r");
+	if (f)
+	{
+		fclose(f);
+		strcpy(errmsg, "key with given name already exists");
+		goto end;
+	}
+	sprintf(out_file_sharekey1, "swanctl\\bpki\\ShareKey1_%s.ssc", key_name);
+
+	if (!strstr(lib->plugins->loaded_plugins(lib->plugins), "contactcrypto"))
+	{
+		strcpy(errmsg, "contactcrypto plugin isn't loaded");
+		goto end;
+	}
+
+	// dn
+	temp = request->get_str(request, NULL, "dn");
+	if (!temp)
+	{
+		strcpy(errmsg, "distinguished name missing");
+		goto end;
+	}
+	data = chunk_from_hex(chunk_from_str(temp), NULL);
+	memcpy(dn, data.ptr, data.len);	
+	chunk_free(&data);
+
+	// san
+	temp = request->get_str(request, NULL, "san");
+	if (temp)
+	{
+		san_value = identification_create_from_string(temp);
+		if (san_value)
+		{
+			san->insert_last(san, san_value);
+		}		
+	}
+
+	// validity
+	validity = request->get_int(request, 0, "validity");
+
+	// govpki
+	temp = request->get_str(request, NULL, "govpki");
+	add_gov_pki = (temp && !strcmp(temp, "true")) ? true : false;	
+
+	// extreq78
+	temp = request->get_str(request, NULL, "extreq78");
+	use_78_ext_req = (temp && !strcmp(temp, "true")) ? true : false;
+
+	// pass
+	temp = request->get_str(request, NULL, "pass");
+	if (!temp)
+	{
+		strcpy(errmsg, "private key password missing");
+		goto end;
+	}
+	pass = chunk_from_hex(chunk_from_str(temp), NULL);
+
+	// cert
+	temp = request->get_str(request, NULL, "cert");
+	if (!temp)
+	{
+		strcpy(errmsg, "output certification request path missing");
+		goto end;
+	}
+	data = chunk_from_hex(chunk_from_str(temp), NULL);
+	memcpy(out_file_certreq, data.ptr, data.len);
+	chunk_free(&data);
+
+	// sharekey2
+	temp = request->get_str(request, NULL, "sharekey2");
+	if (!temp)
+	{
+		strcpy(errmsg, "output second shared key path missing");
+		goto end;
+	}
+	data = chunk_from_hex(chunk_from_str(temp), NULL);
+	memcpy(out_file_sharekey2, data.ptr, data.len);
+	chunk_free(&data);
+
+	// random
+	temp = request->get_str(request, NULL, "random");
+	if (!temp)
+	{
+		strcpy(errmsg, "random missing");
+		goto end;
+	}
+	random = chunk_from_hex(chunk_from_str(temp), NULL);
+
+	// генерируем пару ключей
+	subj_private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_BIGN,
+									  BUILD_KEY_SIZE, 32,
+									  BUILD_KEY_INITIAL_RANDOM, random, BUILD_END);
+	if (!subj_private)
+	{
+		strcpy(errmsg, "generating key pair failed");
+		goto end;
+	}
+
+	// 
+	subj_id = identification_create_from_string(dn);
+	if (subj_id->get_type(subj_id) != ID_DER_ASN1_DN)
+	{
+		strcpy(errmsg, "supplied dn is not a distinguished name");
+		goto end;
+	}
+
+	// формируем запрос на выпуск сертификата
+	INIT(scheme,
+		.scheme = SIGN_BIGN_WITH_HBELT);
+
+	subj_cert = lib->creds->create(lib->creds,
+		CRED_CERTIFICATE, CERT_PKCS10_REQUEST,
+		BUILD_SIGNING_KEY, subj_private,
+		BUILD_SUBJECT, subj_id,
+		BUILD_SUBJECT_ALTNAMES, san,
+		BUILD_SIGNATURE_SCHEME, scheme,
+		BUILD_BPKI_PKCS10, TRUE,
+		BUILD_CERT_VALIDITY, validity,
+		BUILD_POLICY_GOVPKI, add_gov_pki,
+		BUILD_78_EXTS_REQUEST_OID, use_78_ext_req,
+		BUILD_END);
+	if (!subj_cert)
+	{
+		strcpy(errmsg, "generating certification request failed");
+		goto end;
+	}
+
+	// получаем 32 байта случайности из системного ГСЧ
+	rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+	if (!rng)
+	{
+		strcpy(errmsg, "no random number generator found");
+		goto end;
+	}
+	if (!rng_get_bytes_not_zero(rng, 32, seed, FALSE))
+	{
+		strcpy(errmsg, "failed to generate seed");
+		goto end;
+	}
+
+	// конкатенируем случайности, полученные из двух разных источников
+	init_data = chunk_cat("cc", chunk_create(seed, 32), random);
+
+	// хэшируем конкатенацию случайностей
+	hasher = lib->crypto->create_hasher(lib->crypto, BELT_HASH);
+	if (!hasher)
+	{
+		strcpy(errmsg, "no hasher found");
+		goto end;
+	}
+	if (!hasher->allocate_hash(hasher, init_data, &hash_init_data))
+	{
+		strcpy(errmsg, "failed to hash seed");
+		goto end;
+	}
+
+	// инициализируем ГСПЧ по СТБ 34.101.47 полученным хэш-значением
+	prf = lib->crypto->create_prf(lib->crypto, PRF_BRNG_HMAC_HBELT);
+	if (!prf)
+	{
+		strcpy(errmsg, "no pseudorandom number generator found");
+		goto end;
+	}
+	if (!prf->set_key(prf, hash_init_data))
+	{
+		strcpy(errmsg, "initializing pseudorandom number generator failed");
+		goto end;
+	}
+
+	// генерируем высокоэнтропийный ключ
+	hekey_chunk = chunk_alloca(16);
+	if (!prf->get_bytes(prf, hekey_chunk, NULL))
+	{
+		strcpy(errmsg, "generating high entropy key failed");
+		goto end;
+	}
+
+	// разделяем личный ключ на частичные секреты и формируем защищенные контейнеры
+	contactcrypto_private_key_t *private = (contactcrypto_private_key_t*)subj_private;
+	user_pwd = shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(pass));
+	high_entropy_key = shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(hekey_chunk));
+	memwipe(hekey_chunk.ptr, hekey_chunk.len);
+
+	if (!private->command(private, "build-containers", user_pwd, high_entropy_key,
+			&privkey_chunk, &sharekey1_chunk, &sharekey2_chunk))
+	{
+		strcpy(errmsg, "building private key containers failed");
+		goto end;
+	}
+
+	// ---------- save certification request
+	if (!subj_cert->get_encoding(subj_cert, CERT_ASN1_DER, &certreq_chunk))
+	{
+		strcpy(errmsg, "encoding certification request failed");
+		goto end;
+	}
+	f = ext_fopen(out_file_certreq, "wb");
+	if (!f)
+	{
+		strcpy(errmsg, "exporting certification request failed");
+		goto end;
+	}
+	if (fwrite(certreq_chunk.ptr, certreq_chunk.len, 1, f) != 1)
+	{
+		strcpy(errmsg, "writing certification request failed");
+		fclose(f);
+		goto end;
+	}
+	fclose(f);
+	DBG1(DBG_CNT, "certification request for \"%s\" "
+			"successfully built and written to \"%s\"", dn, out_file_certreq);
+
+	// ---------- save private key container
+	f = ext_fopen(out_file_privkey, "wb");
+	if (!f)
+	{
+		strcpy(errmsg, "exporting private key container failed");
+		goto end;
+	}
+	if (fwrite(privkey_chunk.ptr, privkey_chunk.len, 1, f) != 1)
+	{
+		strcpy(errmsg, "writing private key container failed");
+		fclose(f);
+		goto end;
+	}
+	fclose(f);
+	DBG1(DBG_CNT, "private key container for \"%s\" "
+			"successfully built and written to \"%s\"", dn, out_file_privkey);
+
+	// ---------- save first shared secret container
+	f = ext_fopen(out_file_sharekey1, "wb");
+	if (!f)
+	{
+		strcpy(errmsg, "exporting first shared secret container failed");
+		goto end;
+	}
+	if (fwrite(sharekey1_chunk.ptr, sharekey1_chunk.len, 1, f) != 1)
+	{
+		strcpy(errmsg, "writing first shared secret container failed");
+		fclose(f);
+		goto end;
+	}
+	fclose(f);
+	DBG1(DBG_CNT, "first shared secret container for \"%s\" "
+			"successfully built and written to \"%s\"", dn, out_file_sharekey1);
+
+	// ---------- save second shared secret container
+	f = ext_fopen(out_file_sharekey2, "wb");
+	if (!f)
+	{
+		strcpy(errmsg, "exporting second shared secret container failed");
+		goto end;
+	}
+	if (fwrite(sharekey2_chunk.ptr, sharekey2_chunk.len, 1, f) != 1)
+	{
+		strcpy(errmsg, "writing second shared secret container failed");
+		fclose(f);
+		goto end;
+	}
+	fclose(f);
+	DBG1(DBG_CNT, "second shared secret container for \"%s\" "
+			"successfully built and written to \"%s\"", dn, out_file_sharekey2);
+
+end:
+	san->destroy_offset(san, offsetof(identification_t, destroy));
+	DESTROY_IF(subj_private);
+	DESTROY_IF(subj_id);
+	DESTROY_IF(subj_cert);
+	DESTROY_IF(rng);
+	DESTROY_IF(hasher);
+	DESTROY_IF(prf);
+	signature_params_destroy(scheme);
+	chunk_clear(&pass);
+	chunk_clear(&random);
+	chunk_clear(&init_data);
+	chunk_clear(&hash_init_data);
+	DESTROY_IF(user_pwd);
+	DESTROY_IF(high_entropy_key);
+	if (certreq_chunk.ptr != NULL) chunk_free(&certreq_chunk);
+	if (privkey_chunk.ptr != NULL) chunk_free(&privkey_chunk);
+	if (sharekey1_chunk.ptr != NULL) chunk_free(&sharekey1_chunk);
+	if (sharekey2_chunk.ptr != NULL) chunk_free(&sharekey2_chunk);
+
+	if(errmsg[0]) {
+		return create_reply(errmsg);
+	}
+
+	vici_builder_t *b;
+	b = vici_builder_create();
+	b->add_kv(b, "success", "yes");	
+	return b->finalize(b);
+}
+
+CALLBACK(selftest, vici_message_t*,
+	private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
+{
+	char errmsg[1024], *pos, buf[1024];
+	FILE *cmd = NULL;
+	char* crytpotest_bat = "basctl.bat";
+
+	cmd = popen(crytpotest_bat, "r");
+	if (!cmd)
+	{
+		DBG1(DBG_CNT, "self-testing failed: %s", strerror(errno));
+		strcpy(errmsg, "self-testing failed");
+		goto end;
+	}
+	while (TRUE)
+	{
+		if (!fgets(buf, sizeof(buf), cmd))
+		{
+			if (ferror(cmd))
+			{
+				DBG1(DBG_CNT, "self-testing failed: reading from script failed");
+				strcpy(errmsg, "self-testing failed");
+				goto end;
+			}
+			break;
+		}
+		else
+		{
+			pos = buf + strlen(buf);
+			if (pos > buf && pos[-1] == '\n')
+			{
+				pos[-1] = '\0';
+			}
+		}
+	}	
+	if (pclose(cmd) != 0)
+	{
+		DBG1(DBG_CNT, "self-testing failed");
+		strcpy(errmsg, "self-testing failed");
+		goto end;
+	}
+
+	DBG1(DBG_CNT, "self-testing completed successfully");
+	
+	vici_builder_t *b;
+	b = vici_builder_create();
+	b->add_kv(b, "success", "yes");	
+	return b->finalize(b);
+
+end:
+	if (cmd) pclose(cmd);
+	return create_reply(errmsg);
+}
+
+CALLBACK(remove_key, vici_message_t*,
+	private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
+{
+	char *temp, key_name[256] = {0}, file_privkey[1048] = {0}, 
+		 pwd[256] = {0}, file_sharekey1[1048] = {0}, 
+		 file_sharekey2[1048] = {0}, params[2048] = {0};
+	chunk_t data;
+	FILE *f;
+	private_key_t *private = NULL;
+
+	if (!strstr(lib->plugins->loaded_plugins(lib->plugins), "contactcrypto"))
+	{
+		return create_reply("contactcrypto plugin isn't loaded");
+	}
+
+	// keyname
+	temp = request->get_str(request, NULL, "keyname");
+	if (!temp)
+	{
+		return create_reply("key name missing");
+	}
+	data = chunk_from_hex(chunk_from_str(temp), NULL);
+	memcpy(key_name, data.ptr, data.len);
+	chunk_free(&data);
+	
+	sprintf(file_privkey, "swanctl\\bpki\\PrivKey_%s.pkc", key_name);
+	f = ext_fopen(file_privkey, "r");
+	if (!f)
+	{
+		return create_reply("key with given name does not exist");
+	}
+	fclose(f);
+	sprintf(file_sharekey1, "swanctl\\bpki\\ShareKey1_%s.ssc", key_name);
+
+	// pass
+	temp = request->get_str(request, NULL, "pass");
+	if (!temp)
+	{
+		return create_reply("private key password missing");
+	}
+	data = chunk_from_hex(chunk_from_str(temp), NULL);
+
+	memcpy(pwd, data.ptr, data.len);
+	chunk_free(&data);
+
+	// sharekey2
+	temp = request->get_str(request, NULL, "sharekey2");
+	if (!temp)
+	{
+		return create_reply("second shared key path missing");
+	}
+	data = chunk_from_hex(chunk_from_str(temp), NULL);
+	memcpy(file_sharekey2, data.ptr, data.len);
+	chunk_free(&data);
+
+	sprintf(params, "PRIV_KEY=\"%s\" PWD=\"%s\" SHARE_SECR1=\"%s\" SHARE_SECR2=\"%s\"",
+			file_privkey, pwd, file_sharekey1, file_sharekey2);
+	
+	data = chunk_from_str(params);
+	private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_BIGN,
+								 BUILD_BPKI_PARAMS, data, BUILD_END);
+	if (!private)
+	{
+		return create_reply("private key inputs verification failed");
+	}
+	private->destroy(private);
+
+	// удаляем файлы контейнеров
+	if (ext_remove(file_privkey))
+	{
+		return create_reply("removing private key container failed");
+	}
+	ext_remove(file_sharekey1);
+	ext_remove(file_sharekey2);
+
+	DBG1(DBG_CNT, "private key \"%s\" successfully removed", key_name);
+
+	vici_builder_t *b;
+	b = vici_builder_create();
+	b->add_kv(b, "success", "yes");	
+	return b->finalize(b);
+}
+
+CALLBACK(bign_verify, vici_message_t*,
+	private_vici_query_t *this, char *name, u_int id, vici_message_t *request)
+{
+	chunk_t temp, *data_chunk = NULL, *sig_chunk = NULL;
+	char *str, data_file[1024] = {0}, sig_file[1024] = {0};
+	certificate_t *cert = NULL;
+	public_key_t* pubkey = NULL;
+	bool is_valid;
+	
+	if (!strstr(lib->plugins->loaded_plugins(lib->plugins), "contactcrypto"))
+	{
+		return create_reply("contactcrypto plugin isn't loaded");
+	}
+
+	// file
+	str = request->get_str(request, NULL, "file");
+	if (!str)
+	{
+		return create_reply("data file path missing");
+	}
+	temp = chunk_from_hex(chunk_from_str(str), NULL);
+	memcpy(data_file, temp.ptr, temp.len);
+	chunk_free(&temp);
+
+	// signature
+	str = request->get_str(request, NULL, "signature");
+	if (!str)
+	{
+		return create_reply("signature file path missing");
+	}
+	temp = chunk_from_hex(chunk_from_str(str), NULL);
+	memcpy(sig_file, temp.ptr, temp.len);
+	chunk_free(&temp);
+
+	cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+							  BUILD_FROM_FILE, "contact_code_signing.cer", BUILD_END);
+	if(!cert)
+	{
+		return create_reply("parse certificate failed");
+	}
+
+	pubkey = cert->get_public_key(cert);
+	if(!pubkey)
+	{
+		DESTROY_IF(cert);
+		return create_reply("get public key failed");
+	}
+	DESTROY_IF(cert);
+
+	if(!(data_chunk = chunk_map(data_file, FALSE)))
+	{
+		DESTROY_IF(pubkey);
+		return create_reply("read data file failed");
+ 	}
+ 	if(!(sig_chunk = chunk_map(sig_file, FALSE)))
+	{
+		chunk_unmap(data_chunk);
+		DESTROY_IF(pubkey);
+		return create_reply("read signature file failed");
+ 	}
+
+	is_valid = pubkey->verify(pubkey, SIGN_BIGN_WITH_HBELT,
+		                      NULL, *data_chunk, *sig_chunk);
+
+	chunk_unmap(data_chunk);
+	chunk_unmap(sig_chunk);
+	DESTROY_IF(pubkey);
+
+	if (!is_valid)
+	{
+		return create_reply("signature is not valid");
+	}
+
+	vici_builder_t *b;
+	b = vici_builder_create();
+	b->add_kv(b, "success", "yes");	
+	return b->finalize(b);
+}
+
 static void manage_command(private_vici_query_t *this,
 						   char *name, vici_command_cb_t cb, bool reg)
 {
@@ -1694,6 +2308,10 @@
 	manage_command(this, "reset-counters", reset_counters, reg);
 	manage_command(this, "version", version, reg);
 	manage_command(this, "stats", stats, reg);
+	manage_command(this, "build-certreq", build_certreq, reg);
+	manage_command(this, "selftest", selftest, reg);
+	manage_command(this, "remove-key", remove_key, reg);
+	manage_command(this, "bign-verify", bign_verify, reg);
 }
 
 METHOD(listener_t, ike_updown, bool,
diff -ruN strongswan-5.8.4/src/libcharon/sa/authenticator.c strongswancont-5.8.4-svc/src/libcharon/sa/authenticator.c
--- strongswan-5.8.4/src/libcharon/sa/authenticator.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/authenticator.c	2022-07-06 15:47:34.526979000 +0300
@@ -27,11 +27,12 @@
 #include <encoding/payloads/auth_payload.h>
 
 
-ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS,
+ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_BIGN,
 	"RSA signature",
 	"pre-shared key",
-	"DSS signature");
-ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_DS, AUTH_DSS,
+	"DSS signature",
+	"BIGN signature");
+ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_DS, AUTH_BIGN,
 	"ECDSA-256 signature",
 	"ECDSA-384 signature",
 	"ECDSA-521 signature",
@@ -98,6 +99,7 @@
 	switch (auth_payload->get_auth_method(auth_payload))
 	{
 		case AUTH_RSA:
+		case AUTH_BIGN:
 		case AUTH_ECDSA_256:
 		case AUTH_ECDSA_384:
 		case AUTH_ECDSA_521:
@@ -138,6 +140,10 @@
 			return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa,
 										initiator, dh, dh_value, sa_payload,
 										id_payload, KEY_RSA);
+		case AUTH_BIGN:
+			return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa,
+										initiator, dh, dh_value, sa_payload,
+										id_payload, KEY_BIGN);
 		case AUTH_ECDSA_256:
 		case AUTH_ECDSA_384:
 		case AUTH_ECDSA_521:
diff -ruN strongswan-5.8.4/src/libcharon/sa/authenticator.h strongswancont-5.8.4-svc/src/libcharon/sa/authenticator.h
--- strongswan-5.8.4/src/libcharon/sa/authenticator.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/authenticator.h	2022-07-06 15:47:34.510979000 +0300
@@ -58,7 +58,12 @@
 	 * DSS private key over a SHA-1 hash.
 	 */
 	AUTH_DSS = 3,
-
+	
+	/**
+	 *	Computed as in STB 34.101.45
+	 */
+	AUTH_BIGN = 4,
+	
 	/**
 	 * ECDSA with SHA-256 on the P-256 curve as specified in RFC 4754
 	 */
diff -ruN strongswan-5.8.4/src/libcharon/sa/eap/eap_method.h strongswancont-5.8.4-svc/src/libcharon/sa/eap/eap_method.h
--- strongswan-5.8.4/src/libcharon/sa/eap/eap_method.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/eap/eap_method.h	2022-07-06 15:47:34.526979000 +0300
@@ -113,11 +113,17 @@
 	 *
 	 * Not all EAP methods establish a shared secret. For implementations of
 	 * the EAP-Identity method, get_msk() returns the received identity.
+	 * 
+	 * @note Returning NOT_SUPPORTED is important for implementations of EAP
+	 * methods that don't establish an MSK.  In particular as client because
+	 * key-generating EAP methods MUST fail to process EAP-Success messages if
+	 * no MSK is established.
 	 *
 	 * @param msk			chunk receiving internal stored MSK
 	 * @return
-	 *						- SUCCESS, or
+	 *						- SUCCESS, if MSK is established
 	 * 						- FAILED, if MSK not established (yet)
+	 * 						- NOT_SUPPORTED, for non-MSK-establishing methods
 	 */
 	status_t (*get_msk) (eap_method_t *this, chunk_t *msk);
 
diff -ruN strongswan-5.8.4/src/libcharon/sa/ike_sa.c strongswancont-5.8.4-svc/src/libcharon/sa/ike_sa.c
--- strongswan-5.8.4/src/libcharon/sa/ike_sa.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ike_sa.c	2023-06-15 15:43:27.206585000 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2019 Tobias Brunner
+ * Copyright (C) 2006-2020 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -65,6 +65,10 @@
 #include <processing/jobs/initiate_mediation_job.h>
 #endif
 
+#ifdef _WIN32
+#include <windows.h>
+#endif /* _WIN32 */
+
 ENUM(ike_sa_state_names, IKE_CREATED, IKE_DESTROYING,
 	"CREATED",
 	"CONNECTING",
@@ -237,6 +241,12 @@
 	uint32_t keepalive_interval;
 
 	/**
+	 * Time the NAT keep alive interval may be exceeded before triggering a DPD
+	 * instead of a NAT keep alive
+	 */
+	uint32_t keepalive_dpd_margin;
+
+	/**
 	 * The scheduled keep alive job, if any
 	 */
 	send_keepalive_job_t *keepalive_job;
@@ -655,7 +665,19 @@
 
 	diff = now - last_out;
 
-	if (diff >= this->keepalive_interval)
+	if (this->keepalive_dpd_margin &&
+		diff > (this->keepalive_interval + this->keepalive_dpd_margin))
+	{
+		if (!this->task_manager->busy(this->task_manager))
+		{
+			DBG1(DBG_IKE, "sending DPD instead of keep alive %ds after last "
+				 "outbound message", diff);
+			this->task_manager->queue_dpd(this->task_manager);
+			this->task_manager->initiate(this->task_manager);
+		}
+		diff = 0;
+	}
+	else if (diff >= this->keepalive_interval)
 	{
 		packet_t *packet;
 		chunk_t data;
@@ -669,6 +691,7 @@
 		packet->set_data(packet, data);
 		DBG1(DBG_IKE, "sending keep alive to %#H", this->other_host);
 		charon->sender->send_no_marker(charon->sender, packet);
+		this->stats[STAT_OUTBOUND] = now;
 		diff = 0;
 	}
 	if (!this->keepalive_job)
@@ -934,6 +957,17 @@
 	{
 		charon->ike_sa_manager->new_initiator_spi(charon->ike_sa_manager,
 												  &this->public);
+
+		/* when starting from scratch, connect to the original peer again e.g.
+		 * if we got redirected but weren't able to connect successfully */
+		if (this->redirected_from)
+		{
+			this->redirected_from->destroy(this->redirected_from);
+			this->redirected_from = NULL;
+			/* we can't restore the original value, if there was any */
+			DESTROY_IF(this->remote_host);
+			this->remote_host = NULL;
+		}	
 	}
 	/* the responder ID is reset, as peer may choose another one */
 	if (this->ike_sa_id->is_initiator(this->ike_sa_id))
@@ -2145,6 +2179,19 @@
 		return FAILED;
 	}
 
+#ifdef _WIN32
+	int delay = lib->settings->get_int(lib->settings, "%s.create_ike_delay",
+								   0, lib->ns);
+	if (delay > 0)
+	{
+		if (delay > 10000)
+		{
+			delay = 10000;
+		}		
+		SleepEx(delay, TRUE);
+	}
+#endif /* _WIN32 */
+
 	new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
 											   this->version, TRUE);
 	if (!new)
@@ -2287,9 +2334,9 @@
 	reset(this, TRUE);
 	DESTROY_IF(this->redirected_from);
 	this->redirected_from = this->other_host->clone(this->other_host);
-	DESTROY_IF(this->remote_host);
 	/* this allows us to force the remote address while we still properly
 	 * resolve the local address */
+	DESTROY_IF(this->remote_host);
 	this->remote_host = other;
 	resolve_hosts(this);
 	return TRUE;
@@ -2396,81 +2443,86 @@
 	{
 		return INVALID_STATE;
 	}
-	this->stats[STAT_OUTBOUND] = time_monotonic(NULL);
-	if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
+	switch (this->task_manager->retransmit(this->task_manager, message_id))
+	{
+		case SUCCESS:
+			this->stats[STAT_OUTBOUND] = time_monotonic(NULL);
+			return SUCCESS;
+		case INVALID_STATE:
+			return INVALID_STATE;
+		default:
+			break;
+	}
+	/* send a proper signal to brief interested bus listeners */
+	switch (this->state)
 	{
-		/* send a proper signal to brief interested bus listeners */
-		switch (this->state)
+		case IKE_CONNECTING:
 		{
-			case IKE_CONNECTING:
-			{
-				/* retry IKE_SA_INIT/Main Mode if we have multiple keyingtries */
-				uint32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
-				charon->bus->alert(charon->bus, ALERT_PEER_INIT_UNREACHABLE,
-								   this->keyingtry);
-				this->keyingtry++;
-				if (tries == 0 || tries > this->keyingtry)
-				{
-					DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)",
-						 this->keyingtry + 1, tries);
-					reset(this, TRUE);
-					resolve_hosts(this);
-					return this->task_manager->initiate(this->task_manager);
-				}
-				DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding");
-
-				if (this->version == IKEV1 && array_count(this->child_sas))
+			/* retry IKE_SA_INIT/Main Mode if we have multiple keyingtries */
+			uint32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
+			charon->bus->alert(charon->bus, ALERT_PEER_INIT_UNREACHABLE,
+							   this->keyingtry);
+			this->keyingtry++;
+			if (tries == 0 || tries > this->keyingtry)
+			{
+				DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)",
+					 this->keyingtry + 1, tries);
+				reset(this, TRUE);
+				resolve_hosts(this);
+				return this->task_manager->initiate(this->task_manager);
+			}
+			DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding");
+
+			if (this->version == IKEV1 && array_count(this->child_sas))
+			{
+				enumerator_t *enumerator;
+				child_sa_t *child_sa;
+
+				/* if reauthenticating an IKEv1 SA failed (assumed for an SA
+				 * in this state with CHILD_SAs), try again from scratch */
+				DBG1(DBG_IKE, "reauthentication failed, trying to "
+					 "reestablish IKE_SA");
+				reestablish(this);
+				/* trigger down events for the CHILD_SAs, as no down event
+				 * is triggered below for IKE SAs in this state */
+				enumerator = array_create_enumerator(this->child_sas);
+				while (enumerator->enumerate(enumerator, &child_sa))
 				{
-					enumerator_t *enumerator;
-					child_sa_t *child_sa;
-
-					/* if reauthenticating an IKEv1 SA failed (assumed for an SA
-					 * in this state with CHILD_SAs), try again from scratch */
-					DBG1(DBG_IKE, "reauthentication failed, trying to "
-						 "reestablish IKE_SA");
-					reestablish(this);
-					/* trigger down events for the CHILD_SAs, as no down event
-					 * is triggered below for IKE SAs in this state */
-					enumerator = array_create_enumerator(this->child_sas);
-					while (enumerator->enumerate(enumerator, &child_sa))
+					if (child_sa->get_state(child_sa) != CHILD_REKEYED &&
+						child_sa->get_state(child_sa) != CHILD_DELETED)
 					{
-						if (child_sa->get_state(child_sa) != CHILD_REKEYED &&
-							child_sa->get_state(child_sa) != CHILD_DELETED)
-						{
-							charon->bus->child_updown(charon->bus, child_sa,
-													  FALSE);
-						}
+						charon->bus->child_updown(charon->bus, child_sa,
+												  FALSE);
 					}
-					enumerator->destroy(enumerator);
 				}
-				break;
+				enumerator->destroy(enumerator);
 			}
-			case IKE_DELETING:
-				DBG1(DBG_IKE, "proper IKE_SA delete failed, peer not responding");
-				if (has_condition(this, COND_REAUTHENTICATING) &&
-					!lib->settings->get_bool(lib->settings,
-										"%s.make_before_break", FALSE, lib->ns))
-				{
-					DBG1(DBG_IKE, "delete during reauthentication failed, "
-						 "trying to reestablish IKE_SA anyway");
-					reestablish(this);
-				}
-				break;
-			case IKE_REKEYING:
-				DBG1(DBG_IKE, "rekeying IKE_SA failed, peer not responding");
-				/* FALL */
-			default:
-				reestablish(this);
-				break;
-		}
-		if (this->state != IKE_CONNECTING &&
-			this->state != IKE_REKEYED)
-		{
-			charon->bus->ike_updown(charon->bus, &this->public, FALSE);
+			break;
 		}
-		return DESTROY_ME;
+		case IKE_DELETING:
+			DBG1(DBG_IKE, "proper IKE_SA delete failed, peer not responding");
+			if (has_condition(this, COND_REAUTHENTICATING) &&
+				!lib->settings->get_bool(lib->settings,
+									"%s.make_before_break", FALSE, lib->ns))
+			{
+				DBG1(DBG_IKE, "delete during reauthentication failed, "
+					 "trying to reestablish IKE_SA anyway");
+				reestablish(this);
+			}
+			break;
+		case IKE_REKEYING:
+			DBG1(DBG_IKE, "rekeying IKE_SA failed, peer not responding");
+			/* FALL */
+		default:
+			reestablish(this);
+			break;
 	}
-	return SUCCESS;
+	if (this->state != IKE_CONNECTING &&
+		this->state != IKE_REKEYED)
+	{
+		charon->bus->ike_updown(charon->bus, &this->public, FALSE);
+	}
+	return DESTROY_ME;
 }
 
 METHOD(ike_sa_t, set_auth_lifetime, status_t,
@@ -2678,6 +2730,14 @@
 			this->task_manager->queue_mobike(this->task_manager, FALSE, TRUE);
 			return this->task_manager->initiate(this->task_manager);
 		}
+		if (lib->settings->get_bool(lib->settings,
+								"%s.check_current_path", FALSE, lib->ns) &&
+			!this->task_manager->busy(this->task_manager))
+		{
+			DBG1(DBG_IKE, "checking if current path still works using DPD");
+			this->task_manager->queue_dpd(this->task_manager);
+			return this->task_manager->initiate(this->task_manager);
+		}
 		return SUCCESS;
 	}
 
@@ -3171,6 +3231,8 @@
 		.unique_id = ref_get(&unique_id),
 		.keepalive_interval = lib->settings->get_time(lib->settings,
 								"%s.keep_alive", KEEPALIVE_INTERVAL, lib->ns),
+		.keepalive_dpd_margin = lib->settings->get_time(lib->settings,
+								"%s.keep_alive_dpd_margin", 0, lib->ns),
 		.retry_initiate_interval = lib->settings->get_time(lib->settings,
 								"%s.retry_initiate_interval", 0, lib->ns),
 		.flush_auth_cfg = lib->settings->get_bool(lib->settings,
diff -ruN strongswan-5.8.4/src/libcharon/sa/ike_sa.h strongswancont-5.8.4-svc/src/libcharon/sa/ike_sa.h
--- strongswan-5.8.4/src/libcharon/sa/ike_sa.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ike_sa.h	2022-07-06 15:47:34.526979000 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2019 Tobias Brunner
+ * Copyright (C) 2006-2020 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -872,10 +872,11 @@
 	 *
 	 * @param message_id	ID of the request to retransmit
 	 * @return
-	 *						- SUCCESS
-	 *						- NOT_FOUND if request doesn't have to be retransmitted
+	 *						- SUCCESS if retransmit was sent
+	 *						- INVALID_STATE if no retransmit required
+	 *						- DESTROY_ME if this IKE_SA MUST be deleted
 	 */
-	status_t (*retransmit) (ike_sa_t *this, uint32_t message_id);
+	status_t (*retransmit)(ike_sa_t *this, uint32_t message_id);
 
 	/**
 	 * Sends a DPD request to the peer.
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c	2022-07-06 15:47:34.530979000 +0300
@@ -84,6 +84,10 @@
 	{
 		scheme = SIGN_ECDSA_WITH_NULL;
 	}
+	else if (this->type == KEY_BIGN)
+	{
+		scheme = SIGN_BIGN_WITH_HBELT;
+	}
 
 	id = this->ike_sa->get_my_id(this->ike_sa);
 	auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
@@ -171,6 +175,10 @@
 	{
 		scheme = SIGN_ECDSA_WITH_NULL;
 	}
+	else if (this->type == KEY_BIGN)
+	{
+		scheme = SIGN_BIGN_WITH_HBELT;
+	}
 
 	sig_payload = (hash_payload_t*)message->get_payload(message, PLV1_SIGNATURE);
 	if (!sig_payload)
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/keymat_v1.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/keymat_v1.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/keymat_v1.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/keymat_v1.c	2022-07-06 15:47:34.566980000 +0300
@@ -288,6 +288,9 @@
 			return HASH_SHA512;
 		case AUTH_HMAC_MD5_96:
 			return HASH_MD5;
+		case AUTH_BELT_HASH_LEGACY:
+		case AUTH_BELT_HASH:
+			return BELT_HASH;	
 		default:
 			return HASH_UNKNOWN;
 	}
@@ -391,6 +394,7 @@
 		case AUTH_XAUTH_RESP_RSA:
 		case AUTH_HYBRID_INIT_RSA:
 		case AUTH_HYBRID_RESP_RSA:
+		case AUTH_BIGN:
 		{
 			if (!this->prf->set_key(this->prf, nonces) ||
 				!this->prf->allocate_bytes(this->prf, g_xy, &skeyid))
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/phase1.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/phase1.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/phase1.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/phase1.c	2022-07-06 15:47:34.510979000 +0300
@@ -143,11 +143,10 @@
 
 	if (peer_cfg)
 	{	/* as initiator or aggressive responder, use identities */
-		my_auth = get_auth_cfg(peer_cfg, TRUE);
 		other_auth = get_auth_cfg(peer_cfg, FALSE);
-		if (my_auth && other_auth)
+		if (other_auth)
 		{
-			my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY);
+			my_id = this->ike_sa->get_my_id(this->ike_sa);
 			if (peer_cfg->use_aggressive(peer_cfg))
 			{
 				other_id = this->ike_sa->get_other_id(this->ike_sa);
@@ -156,10 +155,7 @@
 			{
 				other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY);
 			}
-			if (my_id)
-			{
-				shared_key = find_shared_key(my_id, me, other_id, other);
-			}
+			shared_key = find_shared_key(my_id, me, other_id, other);
 		}
 	}
 	else
@@ -445,6 +441,9 @@
 								break;
 						}
 						break;
+					case KEY_BIGN:
+						method = AUTH_BIGN;
+						break;
 					default:
 						DBG1(DBG_IKE, "private key of type %N not supported",
 							 key_type_names, private->get_type(private));
@@ -476,8 +475,10 @@
 	{
 		if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY)
 		{
-			/* for any pubkey method, return RSA */
-			return AUTH_RSA;
+			/* for any pubkey method, return based on pubkey method */
+			auth_method_t m = get_pubkey_method(this,
+				get_auth_cfg(peer_cfg, TRUE));
+			return (m == AUTH_BIGN) ? AUTH_BIGN : AUTH_RSA;
 		}
 		if (i2 == AUTH_CLASS_XAUTH)
 		{
@@ -629,6 +630,7 @@
 			if (!me->is_anyaddr(me))
 			{
 				id = identification_create_from_sockaddr(me->get_sockaddr(me));
+				auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
 				auth->add(auth, AUTH_RULE_IDENTITY, id);
 			}
 		}
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/task_manager_v1.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/task_manager_v1.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/task_manager_v1.c	2019-08-27 16:26:53.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/task_manager_v1.c	2022-07-06 15:47:34.570980000 +0300
@@ -199,6 +199,14 @@
 	 */
 	u_int retransmit_tries;
 
+ 	/**
+	 * Maximum number of tries possible with current retransmission settings
+	 * before overflowing the range of uint32_t, which we use for the timeout.
+	 * Note that UINT32_MAX milliseconds equal nearly 50 days, so that doesn't
+	 * make much sense without retransmit_limit anyway.
+	 */
+	u_int retransmit_tries_max;
+
 	/**
 	 * Retransmission timeout
 	 */
@@ -355,7 +363,7 @@
 							u_int mid, u_int retransmitted, array_t *packets)
 {
 	packet_t *packet;
-	uint32_t t, max_jitter;
+	uint32_t t = UINT32_MAX, max_jitter;
 
 	array_get(packets, 0, &packet);
 	if (retransmitted > this->retransmit_tries)
@@ -364,8 +372,12 @@
 		charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND_TIMEOUT, packet);
 		return DESTROY_ME;
 	}
-	t = (uint32_t)(this->retransmit_timeout * 1000.0 *
-					pow(this->retransmit_base, retransmitted));
+	if (!this->retransmit_tries_max ||
+		retransmitted <= this->retransmit_tries_max)
+	{
+		t = (uint32_t)(this->retransmit_timeout * 1000.0 *
+						pow(this->retransmit_base, retransmitted));
+	}
 	if (this->retransmit_limit)
 	{
 		t = min(t, this->retransmit_limit);
@@ -392,7 +404,7 @@
 METHOD(task_manager_t, retransmit, status_t,
 	private_task_manager_t *this, uint32_t seqnr)
 {
-	status_t status = SUCCESS;
+	status_t status = INVALID_STATE;
 
 	if (seqnr == this->initiating.seqnr &&
 		array_count(this->initiating.packets))
@@ -2141,5 +2153,11 @@
 	}
 	this->dpd_send &= 0x7FFFFFFF;
 
+	if (this->retransmit_base > 1)
+	{	/* based on 1000 * timeout * base^try */
+		this->retransmit_tries_max = log(UINT32_MAX/
+										 (1000.0 * this->retransmit_timeout))/
+									 log(this->retransmit_base);
+	}
 	return &this->public;
 }
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c	2018-12-14 18:48:24.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c	2022-07-06 15:47:34.566980000 +0300
@@ -82,6 +82,7 @@
 				case AUTH_XAUTH_RESP_RSA:
 				case AUTH_HYBRID_INIT_RSA:
 				case AUTH_HYBRID_RESP_RSA:
+				case AUTH_BIGN:
 					use = TRUE;
 					break;
 				default:
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c	2018-12-14 18:48:24.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c	2022-07-06 15:47:34.526979000 +0300
@@ -99,8 +99,7 @@
 	id = certreq->get_dn(certreq);
 	if (!id)
 	{
-		DBG1(DBG_IKE, "ignoring certificate request without data",
-			 certificate_type_names, certreq->get_cert_type(certreq));
+		DBG1(DBG_IKE, "ignoring certificate request without data");
 		return NULL;
 	}
 	cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE);
@@ -421,6 +420,7 @@
 				case AUTH_ECDSA_521:
 				case AUTH_XAUTH_INIT_RSA:
 				case AUTH_XAUTH_RESP_RSA:
+				case AUTH_BIGN:
 					use = TRUE;
 					break;
 				default:
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c	2018-10-23 20:03:28.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c	2022-07-06 15:47:34.570980000 +0300
@@ -112,6 +112,10 @@
 	{ "FRAGMENTATION", EXT_IKE_FRAGMENTATION, FALSE, 20,
 	  "\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3\x80\x00\x00\x00"},
 
+	/* Using EXT_STRONGSWAN extension flag to unlock private algorithms */
+	{ "BY-STB Cryptography", EXT_STRONGSWAN, TRUE, 16,
+	  "\xfe\xe9\x32\xef\xe1\x02\x15\xf9\xad\x3c\x3c\xe5\x93\x8a\x5d\x79"},
+
 	/* Windows peers send this VID and a version number */
 	{ "MS NT5 ISAKMPOAKLEY", EXT_MS_WINDOWS, FALSE, 20,
 	  "\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x00"},
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/main_mode.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/main_mode.c
--- strongswan-5.8.4/src/libcharon/sa/ikev1/tasks/main_mode.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev1/tasks/main_mode.c	2022-07-06 15:47:34.566980000 +0300
@@ -302,8 +302,14 @@
 		}
 		case MM_SA:
 		{
+			identification_t *id;
 			uint16_t group;
 
+			/* we might need the identity to look up a PSK when processing the
+			 * response */
+			id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
+			this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
+
 			if (!this->ph1->create_hasher(this->ph1))
 			{
 				return send_notify(this, NO_PROPOSAL_CHOSEN);
@@ -331,8 +337,7 @@
 			id_payload_t *id_payload;
 			identification_t *id;
 
-			id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
-			this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
+			id = this->ike_sa->get_my_id(this->ike_sa);
 			id_payload = id_payload_create_from_identification(PLV1_ID, id);
 			message->add_payload(message, &id_payload->payload_interface);
 
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
--- strongswan-5.8.4/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c	2022-07-06 15:47:34.566980000 +0300
@@ -305,10 +305,28 @@
 				this->method->destroy(this->method);
 				return server_initiate_eap(this, FALSE);
 			}
-			if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
-			{
-				this->msk = chunk_clone(this->msk);
-			}
+			switch (this->method->get_msk(this->method, &this->msk))
+ 			{
+				case SUCCESS:
+					this->msk = chunk_clone(this->msk);
+					if(type == EAP_BSTS || type == EAP_BPACE) 
+					{
+						chunk_t skd;
+						keymat_v2_t *keymat;
+
+						keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+						keymat->get_skd(keymat, &skd);
+
+						memmove(skd.ptr, this->msk.ptr, skd.len);
+					}
+					break;
+				case NOT_SUPPORTED:
+					break;
+				case FAILED:
+				default:
+					DBG1(DBG_IKE, "failed to establish MSK");
+					goto failure;
+ 			}
 			if (vendor)
 			{
 				DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
@@ -326,6 +344,7 @@
 			return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
 		case FAILED:
 		default:
+failure:
 			/* type might have changed for virtual methods */
 			type = this->method->get_type(this->method, &vendor);
 			if (vendor)
@@ -661,11 +680,37 @@
 				uint32_t vendor;
 				auth_cfg_t *cfg;
 
-				if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
-				{
-					this->msk = chunk_clone(this->msk);
-				}
 				type = this->method->get_type(this->method, &vendor);
+
+				if (!this->method)
+ 				{					
+					DBG1(DBG_IKE, "received unexpected %N",
+						 eap_code_names, eap_payload->get_code(eap_payload));
+					return FAILED;
+				}
+				switch (this->method->get_msk(this->method, &this->msk))
+				{
+					case SUCCESS:					
+						this->msk = chunk_clone(this->msk);
+						if(type == EAP_BSTS || type == EAP_BPACE) 
+						{
+							chunk_t skd;
+							keymat_v2_t *keymat =  
+								(keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+							keymat->get_skd(keymat, &skd);
+
+							memmove(skd.ptr, this->msk.ptr, skd.len);
+						}
+						break;
+					case NOT_SUPPORTED:
+						break;
+					case FAILED:
+					default:
+						DBG1(DBG_IKE, "received %N but failed to establish MSK",
+							 eap_code_names, eap_payload->get_code(eap_payload));
+						return FAILED;
+ 				}
+
 				if (vendor)
 				{
 					DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
@@ -747,6 +792,7 @@
 	DESTROY_IF(this->eap_payload);
 	DESTROY_IF(this->eap_identity);
 	chunk_free(&this->msk);
+	DBG4(DBG_LIB,"Освобожден сессионный ключ");
 	free(this);
 }
 
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
--- strongswan-5.8.4/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c	2022-07-06 15:47:34.582980000 +0300
@@ -270,6 +270,13 @@
 				}
 			}
 		}
+		else if (key_type == KEY_BIGN) {
+			scheme = SIGN_BIGN_WITH_HBELT;
+			INIT(config,
+				.scheme = scheme,
+			)
+			array_insert(selected, ARRAY_TAIL, config);
+		}
 	}
 	return selected;
 }
@@ -442,6 +449,10 @@
 			scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
 			auth_method = AUTH_RSA;
 			break;
+		case KEY_BIGN:
+			scheme = SIGN_BIGN_WITH_HBELT;
+			auth_method = AUTH_BIGN;
+			break;	
 		case KEY_ECDSA:
 			/* deduct the signature scheme from the keysize */
 			switch (private->get_keysize(private))
@@ -601,6 +612,10 @@
 			key_type = KEY_RSA;
 			params->scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
 			break;
+		case AUTH_BIGN:
+			key_type = KEY_BIGN;
+			params->scheme = SIGN_BIGN_WITH_HBELT;
+			break;
 		case AUTH_ECDSA_256:
 			params->scheme = SIGN_ECDSA_256;
 			break;
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev2/keymat_v2.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/keymat_v2.c
--- strongswan-5.8.4/src/libcharon/sa/ikev2/keymat_v2.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/keymat_v2.c	2022-07-06 15:47:34.570980000 +0300
@@ -73,6 +73,21 @@
 	chunk_t skp_verify;
 
 	/**
+	 * Key transformer to update skd(msk) (optional)
+	 */
+	key_transformer_t *transformer;
+
+	/**
+	 * skd(msk) level needed by transformer
+	 */
+	chunk_t level;
+
+	/**
+	 * sdk(msk) header needed by transformer
+	 */
+	chunk_t header;	
+
+	/**
 	 * Set of hash algorithms supported by peer for signature authentication
 	 */
 	hash_algorithm_set_t *hash_algorithms;
@@ -306,7 +321,7 @@
 	chunk_t skeyseed = chunk_empty, key, secret, full_nonce, fixed_nonce;
 	chunk_t prf_plus_seed, spi_i, spi_r;
 	prf_plus_t *prf_plus = NULL;
-	uint16_t alg, key_size, int_alg;
+	uint16_t alg, key_tfm_alg, key_size, int_alg;
 	prf_t *rekey_prf = NULL;
 
 	spi_i = chunk_alloca(sizeof(uint64_t));
@@ -335,6 +350,35 @@
 		chunk_clear(&secret);
 		return FALSE;
 	}
+
+	/* Create key transformer if proposed */
+	if (proposal->get_algorithm(proposal, KEY_TRANSFORM_ALGORITHM,
+								&key_tfm_alg, NULL))
+	{
+		DBG1(DBG_IKE, "%N proposed",
+			 transform_type_names, KEY_TRANSFORM_ALGORITHM);
+
+		this->transformer = 
+			lib->crypto->create_key_transformer(lib->crypto, key_tfm_alg);
+
+		if (this->transformer == NULL)
+		{
+			DBG1(DBG_IKE, "%N %N not supported!",
+				 transform_type_names, KEY_TRANSFORM_ALGORITHM,
+				 key_transform_algorithm_names, key_tfm_alg);
+			chunk_clear(&secret);
+			return FALSE;
+		}
+
+		/* allocating level */
+		this->level = chunk_alloc(12);
+		memwipe(this->level.ptr, this->level.len);
+
+		/* allocating header */
+		this->header = chunk_alloc(16);
+		memwipe(this->header.ptr, this->header.len);
+	}
+
 	DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
 	/* full nonce is used as seed for PRF+ ... */
 	full_nonce = chunk_cat("cc", nonce_i, nonce_r);
@@ -651,6 +695,26 @@
 		int_size /= 8;
 	}
 
+	/* update skd(msk) if transformer presents */
+	if (this->transformer)
+	{
+		DBG2(DBG_CHD, "  updating SK_d");
+		DBG4(DBG_CHD, "SK_d %B", &this->skd);
+
+		if(!this->transformer->transform(this->transformer,
+			this->skd, this->skd, this->level, this->header))
+		{
+			DBG1(DBG_CHD, "  updating SK_d failed");
+			return FALSE;
+		}
+
+		DBG4(DBG_CHD, "updated SK_d %B", &this->skd);
+
+		/* increment level by 1 */
+		int k;
+		for(k = 0; (k < 12) && (0 == ++this->level.ptr[k]); k++);
+	}
+
 	if (!this->prf->set_key(this->prf, this->skd))
 	{
 		return FALSE;
@@ -839,9 +903,12 @@
 	DESTROY_IF(this->aead_in);
 	DESTROY_IF(this->aead_out);
 	DESTROY_IF(this->prf);
+	DESTROY_IF(this->transformer);
 	chunk_clear(&this->skd);
 	chunk_clear(&this->skp_verify);
 	chunk_clear(&this->skp_build);
+	chunk_clear(&this->level);
+	chunk_clear(&this->header);
 	DESTROY_IF(this->hash_algorithms);
 	free(this);
 }
@@ -874,6 +941,9 @@
 		},
 		.initiator = initiator,
 		.prf_alg = PRF_UNDEFINED,
+		.transformer = NULL,
+		.level = chunk_empty,
+		.header = chunk_empty,
 	);
 
 	return &this->public;
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev2/task_manager_v2.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/task_manager_v2.c
--- strongswan-5.8.4/src/libcharon/sa/ikev2/task_manager_v2.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/task_manager_v2.c	2023-06-15 15:45:21.029345000 +0300
@@ -103,6 +103,12 @@
 		 */
 		u_int retransmitted;
 
+ 		/**
+		 * TRUE if any retransmits have been sent for this message (counter is
+		 * reset if deferred)
+		 */
+		bool retransmit_sent;
+
 		/**
 		 * packet(s) for retransmission
 		 */
@@ -150,6 +156,14 @@
 	 */
 	u_int retransmit_tries;
 
+ 	/**
+	 * Maximum number of tries possible with current retransmission settings
+	 * before overflowing the range of uint32_t, which we use for the timeout.
+	 * Note that UINT32_MAX milliseconds equal nearly 50 days, so that doesn't
+	 * make much sense without retransmit_limit anyway.
+	 */
+	u_int retransmit_tries_max;
+
 	/**
 	 * Retransmission timeout
 	 */
@@ -331,7 +345,7 @@
 	if (message_id == this->initiating.mid &&
 		array_count(this->initiating.packets))
 	{
-		uint32_t timeout, max_jitter;
+		uint32_t timeout = UINT32_MAX, max_jitter;
 		job_t *job;
 		enumerator_t *enumerator;
 		packet_t *packet;
@@ -357,22 +371,7 @@
 
 		if (!mobike || !mobike->is_probing(mobike))
 		{
-			if (this->initiating.retransmitted <= this->retransmit_tries)
-			{
-				timeout = (uint32_t)(this->retransmit_timeout * 1000.0 *
-					pow(this->retransmit_base, this->initiating.retransmitted));
-
-				if (this->retransmit_limit)
-				{
-					timeout = min(timeout, this->retransmit_limit);
-				}
-				if (this->retransmit_jitter)
-				{
-					max_jitter = (timeout / 100.0) * this->retransmit_jitter;
-					timeout -= max_jitter * (random() / (RAND_MAX + 1.0));
-				}
-			}
-			else
+			if (this->initiating.retransmitted > this->retransmit_tries)
 			{
 				DBG1(DBG_IKE, "giving up after %d retransmits",
 					 this->initiating.retransmitted - 1);
@@ -380,13 +379,28 @@
 								   packet);
 				return DESTROY_ME;
 			}
-
+			if (!this->retransmit_tries_max ||
+				this->initiating.retransmitted <= this->retransmit_tries_max)
+			{
+				timeout = (uint32_t)(this->retransmit_timeout * 1000.0 *
+					pow(this->retransmit_base, this->initiating.retransmitted));
+			}
+			if (this->retransmit_limit)
+			{
+				timeout = min(timeout, this->retransmit_limit);
+			}
+			if (this->retransmit_jitter)
+			{
+				max_jitter = (timeout / 100.0) * this->retransmit_jitter;
+				timeout -= max_jitter * (random() / (RAND_MAX + 1.0));
+			}
 			if (this->initiating.retransmitted)
 			{
 				DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
 					 this->initiating.retransmitted, message_id);
 				charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND, packet,
 								   this->initiating.retransmitted);
+				this->initiating.retransmit_sent = TRUE;
 			}
 			if (!mobike)
 			{
@@ -402,7 +416,7 @@
 						 "deferred");
 					this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
 					this->initiating.deferred = TRUE;
-					return SUCCESS;
+					return INVALID_STATE;
 				}
 				else if (mobike->is_probing(mobike))
 				{
@@ -436,7 +450,7 @@
 					 "deferred");
 				this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
 				this->initiating.deferred = TRUE;
-				return SUCCESS;
+				return INVALID_STATE;
 			}
 		}
 
@@ -444,8 +458,9 @@
 		job = (job_t*)retransmit_job_create(this->initiating.mid,
 											this->ike_sa->get_id(this->ike_sa));
 		lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout);
+		return SUCCESS;
 	}
-	return SUCCESS;
+	return INVALID_STATE;
 }
 
 METHOD(task_manager_t, initiate, status_t,
@@ -627,6 +642,7 @@
 	message->set_exchange_type(message, exchange);
 	this->initiating.type = exchange;
 	this->initiating.retransmitted = 0;
+	this->initiating.retransmit_sent = FALSE;
 	this->initiating.deferred = FALSE;
 
 	enumerator = array_create_enumerator(this->active_tasks);
@@ -747,7 +763,7 @@
 	}
 	enumerator->destroy(enumerator);
 
-	if (this->initiating.retransmitted > 1)
+	if (this->initiating.retransmit_sent)
 	{
 		packet_t *packet = NULL;
 		array_get(this->initiating.packets, 0, &packet);
@@ -2346,5 +2362,11 @@
 					"%s.make_before_break", FALSE, lib->ns),
 	);
 
+	if (this->retransmit_base > 1)
+	{	/* based on 1000 * timeout * base^try */
+		this->retransmit_tries_max = log(UINT32_MAX/
+										 (1000.0 * this->retransmit_timeout))/
+									 log(this->retransmit_base);
+	}
 	return &this->public;
 }
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev2/tasks/child_create.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/tasks/child_create.c
--- strongswan-5.8.4/src/libcharon/sa/ikev2/tasks/child_create.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/tasks/child_create.c	2023-05-13 16:28:02.480139000 +0300
@@ -1853,7 +1853,10 @@
 	{
 		this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
 	}
-
+	if (!this->rekey && !this->retry)
+	{
+		this->dh_group = MODP_NONE;
+	}
 	this->ike_sa = ike_sa;
 	this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
 	this->proposal = NULL;
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev2/tasks/ike_auth.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/tasks/ike_auth.c
--- strongswan-5.8.4/src/libcharon/sa/ikev2/tasks/ike_auth.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/tasks/ike_auth.c	2023-05-13 16:28:32.140877000 +0300
@@ -1009,9 +1009,19 @@
 			if (!this->ike_sa->supports_extension(this->ike_sa,
 												  EXT_EAP_ONLY_AUTHENTICATION))
 			{
-				DBG1(DBG_IKE, "configured EAP-only authentication, but peer "
-					 "does not support it");
-				goto peer_auth_failed;
+				if (lib->settings->get_bool(lib->settings,
+							"%s.force_eap_only_authentication", FALSE, lib->ns))
+				{
+					DBG1(DBG_IKE, "ignore missing %N notify and use EAP-only "
+						 "authentication", notify_type_names,
+						 EAP_ONLY_AUTHENTICATION);
+				}
+				else
+				{
+					DBG1(DBG_IKE, "configured EAP-only authentication, but "
+						 "peer does not support it");
+					goto peer_auth_failed;
+				}
 			}
 		}
 		else
diff -ruN strongswan-5.8.4/src/libcharon/sa/ikev2/tasks/ike_cert_post.c strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/tasks/ike_cert_post.c
--- strongswan-5.8.4/src/libcharon/sa/ikev2/tasks/ike_cert_post.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/ikev2/tasks/ike_cert_post.c	2023-03-24 10:58:46.666283000 +0300
@@ -130,11 +130,13 @@
 	cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
 	if (!cert)
 	{
+		DBG1(DBG_IKE, "tryed to send end entity cert but failed on get");
 		return FALSE;
 	}
 	payload = build_cert_payload(this, cert);
 	if (!payload)
 	{
+		DBG1(DBG_IKE, "tryed to send end entity cert but failed on build");
 		return FALSE;
 	}
 	DBG1(DBG_IKE, "sending end entity cert \"%Y\"", cert->get_subject(cert));
diff -ruN strongswan-5.8.4/src/libcharon/sa/keymat.c strongswancont-5.8.4-svc/src/libcharon/sa/keymat.c
--- strongswan-5.8.4/src/libcharon/sa/keymat.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/keymat.c	2022-07-06 15:47:34.610981000 +0300
@@ -65,6 +65,11 @@
 	keylen_entry_t map[] = {
 		{ENCR_DES,					 64},
 		{ENCR_3DES,					192},
+		{ENCR_GOST28147_CTR,		256},
+		{ENCR_GOST28147_CFB,		256},
+		{ENCR_BELT_CBC,				256},
+		{ENCR_BELT_CFB,				256},
+		{ENCR_BELT_CTR,				256},
 		{ENCR_CHACHA20_POLY1305,	256},
 	};
 	int i;
@@ -95,6 +100,14 @@
 		{AUTH_HMAC_SHA2_512_256,	512},
 		{AUTH_AES_XCBC_96,			128},
 		{AUTH_AES_CMAC_96,			128},
+		{AUTH_BELT_HASH_LEGACY,		256},
+		{AUTH_GOST_MAC_LEGACY,		256},
+		{AUTH_BELT_MAC_LEGACY,		256},
+		{AUTH_BELT_HMAC_LEGACY,		256},
+		{AUTH_BELT_HASH,			256},
+		{AUTH_GOST_MAC,				256},
+		{AUTH_BELT_MAC,				256},
+		{AUTH_BELT_HMAC,			256},
 	};
 	int i;
 
diff -ruN strongswan-5.8.4/src/libcharon/sa/task_manager.c strongswancont-5.8.4-svc/src/libcharon/sa/task_manager.c
--- strongswan-5.8.4/src/libcharon/sa/task_manager.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libcharon/sa/task_manager.c	2022-07-06 15:47:34.610981000 +0300
@@ -25,7 +25,7 @@
 u_int task_manager_total_retransmit_timeout()
 {
 	double timeout, base, limit = 0, total = 0;
-	int tries, i;
+	int tries, max_tries = 0, i;
 
 	tries = lib->settings->get_int(lib->settings, "%s.retransmit_tries",
 								   RETRANSMIT_TRIES, lib->ns);
@@ -36,9 +36,18 @@
 	limit = lib->settings->get_double(lib->settings, "%s.retransmit_limit",
 									  0, lib->ns);
 
+	if (base > 1)
+	{
+		max_tries = log(UINT32_MAX/(1000.0 * timeout))/log(base);
+	}
+
 	for (i = 0; i <= tries; i++)
 	{
-		double interval = timeout * pow(base, i);
+		double interval = UINT32_MAX/1000.0;
+		if (max_tries && i <= max_tries)
+		{
+			interval = timeout * pow(base, i);
+		}
 		if (limit)
 		{
 			interval = min(interval, limit);
diff -ruN strongswan-5.8.4/src/libipsec/codel_queue.c strongswancont-5.8.4-svc/src/libipsec/codel_queue.c
--- strongswan-5.8.4/src/libipsec/codel_queue.c	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libipsec/codel_queue.c	2020-11-30 16:52:55.000000000 +0300
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "codel_queue.h"
+
+#include <threading/thread.h>
+#include <threading/mutex.h>
+#include <threading/condvar.h>
+#include <collections/linked_list.h>
+
+#include <math.h>
+
+typedef struct private_codel_queue_t private_codel_queue_t;
+
+/**
+ * Timestamp with "good" resolution
+ */
+typedef uint64_t timestamp_t;
+
+/**
+ * Entry for an packet
+ */
+typedef struct {
+	void *packet;
+	timestamp_t stamp;
+	u_int len;
+} entry_t;
+
+/**
+ * Private data of an codel_queue_t object.
+ */
+struct private_codel_queue_t {
+
+	/**
+	 * Public codel_queue_t interface.
+	 */
+	codel_queue_t public;
+
+	/**
+	 * Linked list containing all items in the queue
+	 */
+	linked_list_t *list;
+
+	/**
+	 * Offset of object destructor for queued entry packets
+	 */
+	int destroy_offset;
+
+	/**
+	 * Mutex used to synchronize access to the queue
+	 */
+	mutex_t *mutex;
+
+	/**
+	 * Condvar used to wait for items
+	 */
+	condvar_t *condvar;
+
+	/**
+	 * Time when we'll declare we're above target (0 if below)
+	 */
+	timestamp_t first_above;
+
+	/**
+	 * Time to drop next packet
+	 */
+	timestamp_t drop_next;
+
+	/**
+	 * Packets dropped since going into drop state
+	 */
+	u_int count;
+
+	/**
+	 * Size of queue, in bytes
+	 */
+	u_int len;
+
+	/**
+	 * TRUE if in drop state
+	 */
+	bool dropping;
+
+	/**
+	 * Target queue delay
+	 */
+	timestamp_t target;
+
+	/**
+	 * Sliding minimum time window width
+	 */
+	timestamp_t interval;
+
+	/**
+	 * Maximum packet size in bytes (should use interface MTU)
+	 */
+	u_int maxpacket;
+};
+
+/**
+ * Create a timestamp for now
+ */
+static timestamp_t timestamp_now()
+{
+	timeval_t tv;
+
+	time_monotonic(&tv);
+
+	return tv.tv_sec * 1000 * 1000 + tv.tv_usec;
+}
+
+/**
+ * Convert miliseconds to timestamp_now() resolution
+ */
+static timestamp_t timestamp_from_ms(u_int ms)
+{
+	return ms * 1000;
+}
+
+/**
+ * Calculate frequency for dropping
+ */
+static timestamp_t control_law(private_codel_queue_t *this, timestamp_t t)
+{
+	return t + this->interval / (timestamp_t)sqrt(this->count);
+}
+
+/**
+ * Destroy a packet with the destructor offset
+ */
+static void destroy_packet(private_codel_queue_t *this, void *packet)
+{
+	void (**method)(void*);
+
+	method = packet + this->destroy_offset;
+	(*method)(packet);
+}
+
+METHOD(codel_queue_t, enqueue, void,
+	private_codel_queue_t *this, void *packet, u_int len)
+{
+	entry_t *entry;
+
+	INIT(entry,
+		.packet = packet,
+		.len = len,
+		.stamp = timestamp_now(),
+	);
+
+	this->mutex->lock(this->mutex);
+
+	this->list->insert_first(this->list, entry);
+	this->len += len;
+
+	this->mutex->unlock(this->mutex);
+
+	this->condvar->signal(this->condvar);
+}
+
+/**
+ * Dequeue an entry
+ */
+static entry_t* dequeue_entry(private_codel_queue_t *this)
+{
+	entry_t *entry;
+	bool oldstate;
+
+	thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
+
+	/* ensure that a canceled thread does not dequeue any items */
+	thread_cancellation_point();
+
+	while (this->list->remove_last(this->list, (void**)&entry) != SUCCESS)
+	{
+		/* queue empty, get out of dropping state */
+		this->first_above = 0;
+		this->dropping = FALSE;
+
+		oldstate = thread_cancelability(TRUE);
+		this->condvar->wait(this->condvar, this->mutex);
+		thread_cancelability(oldstate);
+	}
+
+	thread_cleanup_pop(FALSE);
+
+	return entry;
+}
+
+/**
+ * CoDelized dequeue of a packet
+ */
+static void* dequeue_packet(private_codel_queue_t *this, timestamp_t now,
+							bool *ok_to_drop)
+{
+	entry_t *entry;
+	timestamp_t sojourn;
+	void *packet;
+
+	*ok_to_drop = FALSE;
+
+	entry = dequeue_entry(this);
+
+	this->len -= entry->len;
+	sojourn = now - entry->stamp;
+	if (sojourn < this->target || this->len < this->maxpacket)
+	{
+		/* below target delay */
+		this->first_above = 0;
+	}
+	else
+	{
+		if (this->first_above == 0)
+		{
+			/* first time above target delay */
+			this->first_above = now + this->interval;
+		}
+		else if (now >= this->first_above)
+		{
+			/* have been obove target delay for interval */
+			*ok_to_drop = TRUE;
+		}
+	}
+
+	packet = entry->packet;
+	free(entry);
+
+	return packet;
+}
+
+METHOD(codel_queue_t, dequeue, void*,
+	private_codel_queue_t *this)
+{
+	timestamp_t now;
+	bool ok_to_drop;
+	void *packet;
+
+	now = timestamp_now();
+
+	this->mutex->lock(this->mutex);
+
+	packet = dequeue_packet(this, now, &ok_to_drop);
+	if (this->dropping)
+	{
+		if (!ok_to_drop)
+		{
+			/* stop dropping after queue delay got acceptable */
+			this->dropping = FALSE;
+		}
+		else if (now >= this->drop_next)
+		{
+			/* continue dropping dropping packets more and more aggressively,
+			 * until queue delay gets acceptable */
+			while (now >= this->drop_next && this->dropping)
+			{
+				this->count++;
+				destroy_packet(this, packet);
+				packet = dequeue_packet(this, now, &ok_to_drop);
+				if (!ok_to_drop)
+				{
+					this->dropping = FALSE;
+				}
+				else
+				{
+					this->drop_next = control_law(this, this->drop_next);
+				}
+			}
+		}
+	}
+	else if (ok_to_drop)
+	{
+		if (now < this->drop_next + this->interval ||
+			now >= this->first_above + this->interval)
+		{
+			/* start dropping packets */
+			destroy_packet(this, packet);
+			packet = dequeue_packet(this, now, &ok_to_drop);
+			this->dropping = TRUE;
+
+			if (now < this->drop_next + this->interval)
+			{
+				if (this->count > 2)
+				{
+					this->count -= 2;
+				}
+				else
+				{
+					 this->count = 1;
+				}
+			}
+			else
+			{
+				this->count = 1;
+				this->drop_next = control_law(this, now);
+			}
+		}
+	}
+
+	this->mutex->unlock(this->mutex);
+
+	return packet;
+}
+
+METHOD(codel_queue_t, destroy, void,
+	private_codel_queue_t *this)
+{
+	entry_t *entry;
+
+	while (this->list->remove_last(this->list, (void**)&entry) == SUCCESS)
+	{
+		destroy_packet(this, entry->packet);
+		free(entry);
+	}
+	this->list->destroy(this->list);
+	this->condvar->destroy(this->condvar);
+	this->mutex->destroy(this->mutex);
+	free(this);
+}
+
+/**
+ * See header
+ */
+codel_queue_t *codel_queue_create(int destroy_offset, u_int mtu)
+{
+	private_codel_queue_t *this;
+
+	INIT(this,
+		.public = {
+			.enqueue = _enqueue,
+			.dequeue = _dequeue,
+			.destroy = _destroy,
+		},
+		.list = linked_list_create(),
+		.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+		.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+		.destroy_offset = destroy_offset,
+		.maxpacket = mtu,
+		.target = timestamp_from_ms(5),
+		.interval = timestamp_from_ms(100),
+	);
+
+	return &this->public;
+}
diff -ruN strongswan-5.8.4/src/libipsec/codel_queue.h strongswancont-5.8.4-svc/src/libipsec/codel_queue.h
--- strongswan-5.8.4/src/libipsec/codel_queue.h	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libipsec/codel_queue.h	2020-11-30 16:52:55.000000000 +0300
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup codel_queue codel_queue
+ * @{ @ingroup ipsec
+ */
+
+#ifndef CODEL_QUEUE_H_
+#define CODEL_QUEUE_H_
+
+typedef struct codel_queue_t codel_queue_t;
+
+#include <library.h>
+
+/**
+ * A CoDel implementation.
+ *
+ * Implements a packet queue with "Controlled Delay", as described on
+ *    http://queue.acm.org/detail.cfm?id=2209336
+ */
+struct codel_queue_t {
+
+	/**
+	 * Enqueue a packet to the CoDel queue.
+	 *
+	 * @param packet		packet to enqueue
+	 * @param len			len of packet to enqueue
+	 */
+	void (*enqueue)(codel_queue_t *this, void *packet, u_int len);
+
+	/**
+	 * Dequeue a queued packet from the CoDel queue.
+	 *
+	 * This call is blocking and does not return before a packet could be
+	 * dequeued.
+	 *
+	 * @return				dequeued packet
+	 */
+	void* (*dequeue)(codel_queue_t *this);
+
+	/**
+	 * Destroy a codel_queue_t, with all queued packets.
+	 */
+	void (*destroy)(codel_queue_t *this);
+};
+
+/**
+ * Create a codel_queue instance.
+ *
+ * @param destroy_offset		offset of destructor in queued packet objects
+ * @param mtu				maximum transfer unit of queue link
+ */
+codel_queue_t *codel_queue_create(int destroy_offset, u_int mtu);
+
+#endif /** CODEL_QUEUE_H_ @}*/
diff -ruN strongswan-5.8.4/src/libipsec/ipsec_processor.c strongswancont-5.8.4-svc/src/libipsec/ipsec_processor.c
--- strongswan-5.8.4/src/libipsec/ipsec_processor.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libipsec/ipsec_processor.c	2022-07-08 13:43:01.025711000 +0300
@@ -15,11 +15,11 @@
 
 #include "ipsec.h"
 #include "ipsec_processor.h"
+#include "codel_queue.h"
 
 #include <utils/debug.h>
 #include <library.h>
 #include <threading/rwlock.h>
-#include <collections/blocking_queue.h>
 #include <processing/jobs/callback_job.h>
 
 typedef struct private_ipsec_processor_t private_ipsec_processor_t;
@@ -37,12 +37,12 @@
 	/**
 	 * Queue for inbound packets (esp_packet_t*)
 	 */
-	blocking_queue_t *inbound_queue;
+	codel_queue_t *inbound_queue;
 
 	/**
 	 * Queue for outbound packets (ip_packet_t*)
 	 */
-	blocking_queue_t *outbound_queue;
+	codel_queue_t *outbound_queue;
 
 	/**
 	 * Registered inbound callback
@@ -59,6 +59,14 @@
 		ipsec_outbound_cb_t cb;
 		void *data;
 	} outbound;
+	
+	/**
+	 * Registered acquire callback
+	 */
+	struct {
+		ipsec_acquire_cb_t cb;
+		void *data;
+	} acquire;
 
 	/**
 	 * Lock used to synchronize access to the callbacks
@@ -209,7 +217,24 @@
 	sa = ipsec->sas->checkout_by_reqid(ipsec->sas, policy->get_reqid(policy),
 									   FALSE);
 	if (!sa)
-	{	/* TODO-IPSEC: send an acquire to upper layer */
+	{
+		this->lock->read_lock(this->lock);
+		if (this->acquire.cb)
+		{
+			uint32_t reqid = policy->get_reqid(policy);
+			traffic_selector_t *source_ts = policy->get_source_ts(policy),
+				*destination_ts = policy->get_destination_ts(policy);
+
+			source_ts = source_ts->clone(source_ts);
+			destination_ts = destination_ts->clone(destination_ts);
+
+			this->acquire.cb(this->acquire.data, reqid, source_ts, destination_ts);
+		}
+		else
+		{
+			DBG2(DBG_ESP, "No acquire callback registered.");
+		}
+		this->lock->unlock(this->lock);
 		DBG1(DBG_ESP, "could not find an outbound IPsec SA for reqid {%u}, "
 			 "dropping packet", policy->get_reqid(policy));
 		packet->destroy(packet);
@@ -238,13 +263,15 @@
 METHOD(ipsec_processor_t, queue_inbound, void,
 	private_ipsec_processor_t *this, esp_packet_t *packet)
 {
-	this->inbound_queue->enqueue(this->inbound_queue, packet);
+	this->inbound_queue->enqueue(this->inbound_queue, packet,
+								packet->packet.get_data(&packet->packet).len);
 }
 
 METHOD(ipsec_processor_t, queue_outbound, void,
 	private_ipsec_processor_t *this, ip_packet_t *packet)
 {
-	this->outbound_queue->enqueue(this->outbound_queue, packet);
+	this->outbound_queue->enqueue(this->outbound_queue, packet,
+								packet->get_encoding(packet).len);
 }
 
 METHOD(ipsec_processor_t, register_inbound, void,
@@ -287,13 +314,31 @@
 	this->lock->unlock(this->lock);
 }
 
+METHOD(ipsec_processor_t, register_acquire, void,
+	private_ipsec_processor_t *this, ipsec_acquire_cb_t cb, void *data)
+{
+	this->lock->write_lock(this->lock);
+	this->acquire.cb = cb;
+	this->acquire.data = data;
+	this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_processor_t, unregister_acquire, void,
+	private_ipsec_processor_t *this, ipsec_acquire_cb_t cb)
+{
+	this->lock->write_lock(this->lock);
+	if (this->acquire.cb == cb)
+	{
+		this->acquire.cb = NULL;
+	}
+	this->lock->unlock(this->lock);
+}
+
 METHOD(ipsec_processor_t, destroy, void,
 	private_ipsec_processor_t *this)
 {
-	this->inbound_queue->destroy_offset(this->inbound_queue,
-										offsetof(esp_packet_t, destroy));
-	this->outbound_queue->destroy_offset(this->outbound_queue,
-										 offsetof(ip_packet_t, destroy));
+	this->inbound_queue->destroy(this->inbound_queue);
+	this->outbound_queue->destroy(this->outbound_queue);
 	this->lock->destroy(this->lock);
 	free(this);
 }
@@ -313,10 +358,14 @@
 			.unregister_inbound = _unregister_inbound,
 			.register_outbound = _register_outbound,
 			.unregister_outbound = _unregister_outbound,
+			.register_acquire = _register_acquire,
+			.unregister_acquire = _unregister_acquire,			
 			.destroy = _destroy,
 		},
-		.inbound_queue = blocking_queue_create(),
-		.outbound_queue = blocking_queue_create(),
+		.inbound_queue = codel_queue_create(
+						offsetof(esp_packet_t, destroy), 1500),
+		.outbound_queue = codel_queue_create(
+						offsetof(ip_packet_t, destroy), 1500),
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
 	);
 
diff -ruN strongswan-5.8.4/src/libipsec/ipsec_processor.h strongswancont-5.8.4-svc/src/libipsec/ipsec_processor.h
--- strongswan-5.8.4/src/libipsec/ipsec_processor.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libipsec/ipsec_processor.h	2022-07-08 13:44:24.979579000 +0300
@@ -46,6 +46,17 @@
 typedef void (*ipsec_outbound_cb_t)(void *data, esp_packet_t *packet);
 
 /**
+ * Callback called to raise acquire events.
+ * 
+ * @param data				data supplied during registration of the callback
+ * @param reqid				reqid of the matched IPsec policy
+ * @param source_ts			source traffic selector that the packet matched
+ * @param destination_ts	destinationtraffic selector that the packet matched
+ */
+typedef void (*ipsec_acquire_cb_t)(void *data, uint32_t reqid,
+	traffic_selector_t *source_ts, traffic_selector_t *destination_ts);
+
+/**
  *  IPsec processor
  */
 struct ipsec_processor_t {
@@ -98,6 +109,22 @@
 	void (*unregister_outbound)(ipsec_processor_t *this,
 								ipsec_outbound_cb_t cb);
 
+ 	/**
+	 * Register the callback used to raise an acquire event.
+	 * 
+	 * @param cb			the callback function
+	 * @param data			optional data provided to the callback
+	 */
+	void (*register_acquire)(ipsec_processor_t *this, ipsec_acquire_cb_t cb,
+							void *data);
+	
+	/**
+	 * Unregister a previously registered acquire callback.
+	 * 
+	 * @param cb			previously registered acquire callback
+	 */
+	void (*unregister_acquire)(ipsec_processor_t *this, ipsec_acquire_cb_t cb);
+
 	/**
 	 * Destroy an ipsec_processor_t.
 	 */
diff -ruN strongswan-5.8.4/src/libipsec/Makefile.am strongswancont-5.8.4-svc/src/libipsec/Makefile.am
--- strongswan-5.8.4/src/libipsec/Makefile.am	2018-05-28 14:30:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libipsec/Makefile.am	2022-07-08 13:45:59.357674000 +0300
@@ -5,6 +5,7 @@
 esp_context.c esp_context.h \
 esp_packet.c esp_packet.h \
 ip_packet.c ip_packet.h \
+codel_queue.c codel_queue.h \
 ipsec_event_listener.h \
 ipsec_event_relay.c ipsec_event_relay.h \
 ipsec_policy.c ipsec_policy.h \
@@ -18,6 +19,8 @@
 
 if USE_WINDOWS
   libipsec_la_LIBADD += -lws2_32
+else
+  libipsec_la_LIBADD += -lm
 endif
 
 AM_CPPFLAGS = \
diff -ruN strongswan-5.8.4/src/libstrongswan/Android.mk strongswancont-5.8.4-svc/src/libstrongswan/Android.mk
--- strongswan-5.8.4/src/libstrongswan/Android.mk	2019-11-21 14:55:54.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/Android.mk	2022-07-06 15:47:34.750983000 +0300
@@ -15,7 +15,7 @@
 crypto/rngs/rng.c crypto/rngs/rng_tester.c \
 crypto/prf_plus.c crypto/signers/signer.c \
 crypto/signers/mac_signer.c crypto/crypto_factory.c crypto/crypto_tester.c \
-crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \
+crypto/diffie_hellman.c crypto/aead.c crypto/transform.c crypto/key_transformer.c \
 crypto/iv/iv_gen.c crypto/iv/iv_gen_rand.c crypto/iv/iv_gen_seq.c \
 crypto/iv/iv_gen_null.c \
 crypto/xofs/xof.c crypto/xofs/xof_bitspender.c \
diff -ruN strongswan-5.8.4/src/libstrongswan/asn1/oid.txt strongswancont-5.8.4-svc/src/libstrongswan/asn1/oid.txt
--- strongswan-5.8.4/src/libstrongswan/asn1/oid.txt	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/asn1/oid.txt	2022-07-06 15:47:34.750983000 +0300
@@ -29,6 +29,8 @@
     0x0B                     "OU"						OID_ORGANIZATION_UNIT
     0x0C                     "T"						OID_TITLE
     0x0D                     "D"						OID_DESCRIPTION
+    0x0E                     "SG"           OID_SEARCH_GUIDE
+    0x0F                     "BC"           OID_BUISINESS_CATEGORY
     0x10                     "postalAddress"			OID_POSTAL_ADDRESS
     0x11                     "postalCode"				OID_POSTAL_CODE
     0x24                     "userCertificate"			OID_USER_CERTIFICATE
@@ -40,11 +42,12 @@
     0x36                     "dmdName"					OID_DMD_NAME
     0x41                     "pseudonym"				OID_PSEUDONYM
     0x48                     "role"						OID_ROLE
+    0x61                     "organizationIdentifier" OID_ORGANIZATION_ID
   0x1D                       "id-ce"
     0x09                     "subjectDirectoryAttrs"
     0x0E                     "subjectKeyIdentifier"		OID_SUBJECT_KEY_ID
     0x0F                     "keyUsage"					OID_KEY_USAGE
-    0x10                     "privateKeyUsagePeriod"
+    0x10                     "privateKeyUsagePeriod"          OID_PRIVATE_KEY_VALIDITY
     0x11                     "subjectAltName"			OID_SUBJECT_ALT_NAME
     0x12                     "issuerAltName"
     0x13                     "basicConstraints"			OID_BASIC_CONSTRAINTS
@@ -81,6 +84,23 @@
                     0x02     "camellia128-cbc"			OID_CAMELLIA128_CBC
                     0x03     "camellia192-cbc"			OID_CAMELLIA192_CBC
                     0x04     "camellia256-cbc"			OID_CAMELLIA256_CBC
+  0x85                       ""
+    0x03                     "RU"
+      0x02                   ""
+        0x02                 ""
+          0x03               "GOST-R_34.11_34.10-2001"
+          0x04               "GOST-R_34.11_34.10-94"
+          0x09               "GOST-R_34.11-94"
+          0x13               "GOST-R_34.10-2001"
+          0x14               "GOST-R_34.10-94"
+          0x15               "GOST_28147-89"
+      0x06                   "PartnersPermissions"
+        0x03                 ""
+          0x01               ""
+            0x02             "LegalStatus"
+              0x01           "ArtificalPerson"
+              0x02           "PrivatePerson"
+              0x03           "SmallUndertaker"
   0x86                       ""
     0x48                     "us"
       0x86                   ""
@@ -200,6 +220,103 @@
               0x02           "ecdsa-with-SHA256"		OID_ECDSA_WITH_SHA256
               0x03           "ecdsa-with-SHA384"		OID_ECDSA_WITH_SHA384
               0x04           "ecdsa-with-SHA512"		OID_ECDSA_WITH_SHA512
+  0x70                       "BY"
+    0x00                     "by-Standard"
+      0x02                   "by-STD"
+        0x00                 "by-STB"
+          0x22               ""
+            0x65             ""
+              0x1F           "Belt"
+                0x17         "belt-cbc256"            OID_BELT_CBC
+                0x21         "belt-cfb256"            OID_BELT_CFB
+                0x2B         "belt-ctr256"            OID_BELT_CTR
+                0x35         "belt-mac256"            OID_BELT_MAC
+                0x49         "belt-keywrap256"        OID_BELT_KEYWRAP
+                0x51         "belt-hash256"           OID_BELT_HASH
+              0x2D           "Bign"
+                0x01         "BignModule"
+                  0x01       "BignModule_v1"
+                  0x02       "BignModule_v2"
+                0x02         "BignKeys"
+                  0x01       "BignPubKey"             OID_BIGN_PUB_KEY
+                0x03         "BignCurves" 
+                  0x01       "BignCurve256v1"         OID_BIGN_CURVE_256_V1
+                  0x02       "BignCurve384v1"         OID_BIGN_CURVE_384_V1
+                  0x03       "BignCurve512v1"         OID_BIGN_CURVE_512_V1
+                0x04         "BignFields"
+                  0x01       "BignPrimeField"
+                0x0B         "BignWithSpecHash"       OID_SPEC_HASH
+                0x0C         "BignWithBeltHash"       OID_HASH_BELT
+                0x15         "BignGenEC"
+                0x16         "BignValEC"
+                0x1F         "BignGenKeyPair"
+                0x20         "BignValPubKey"
+                0x29         "BignKeyTransport"
+                0x3D         "BignGenK"
+                0x47         "BignIBSwithSpecHash"
+                0x48         "BignIBSwithBeltHash"
+              0x2F           "Brng"
+                0x0C         "hmac-hbelt"             OID_BELT_HMAC
+                0x16         "brng-ctr-hbelt"         OID_BRNG_CTR_HBELT
+                0x20         "brng-hmac-hbelt"        OID_BRNG_HMAC_HBELT
+              0x3C           "Bels"
+                0x02         "bels-m0"
+                  0x01       "bels-m0128v1"           OID_BELS_M0_128_V1
+                  0x02       "bels-m0192v1"           OID_BELS_M0_192_V1
+                  0x03       "bels-m0256v1"           OID_BELS_M0_256_V1
+                0x0B         "bels-share"             OID_BELS_SHARE
+              0x42           "Bake"
+                0x0C         "bake-bsts"
+                0x15         "bake-bpace"
+              0x4E           "Bpki"
+                0x02         "bpki-role"
+                  0x46       "bpki-role-acd"          OID_BPKI_ROLE_ACD
+                0x04         "at"
+                  0x01       "certificateValidity"    OID_BPKI_AT_CERTIFICATE_VALIDITY
+          0x89               ""
+            0x18             "1176"
+              0x02           "STB_1176.2-99"
+                0x01         "STB_1176.2-99_Module"
+                  0x01       "STB_1176.2-99_Module_v1"          OID_MODULE_V1
+                0x02         "STB_1176.2-99_Keys"
+                  0x01       "STB_1176.2-99_PubKey"             OID_PUB_KEY
+                  0x02       "STB_1176.2-99_PrePubKey"          OID_PRE_PUB_KEY
+                  0x03       "STB_1176.2-99_BDH-PubKey"         OID_BDH_PUB_KEY
+                  0x04       "STB_1176.2-99_BDH-PrePubKey"      OID_BDH_PRE_PUB_KEY
+                0x03         "STB_1176.2-99_Params"
+                  0x03       "STB_1176.2-99_BDS_BDH_3"
+                    0x01     "STB_1176.2-99_BDS_3"              OID_BDS_3
+                    0x02     "STB_1176.2-99_BDH_3"              OID_BDH_3
+                  0x06       "STB_1176.2-99_BDS_BDH_6"
+                    0x01     "STB_1176.2-99_BDS_6"              OID_BDS_6
+                    0x02     "STB_1176.2-99_BDH_6"              OID_BDH_6
+                  0x0A       "STB_1176.2-99_BDS_BDH_10"
+                    0x01     "STB_1176.2-99_BDS_10"             OID_BDS_10
+                    0x02     "STB_1176.2-99_BDH_10"             OID_BDH_10
+                0x0B         "STB_1176.2-99_Sign"               OID_SIGN
+                0x0C         "STB_1176.2-99_PreSign"            OID_PRE_SIGN
+                0x15         "STB_1176.2-99_GenParam"           OID_GEN_PARAM
+                0x1F         "STB_1176.2-99_BDH_NoAuth"         OID_BDH_NO_AUTH
+                0x20         "STB_1176.2-99_BDH_Auth"           OID_BDH_AUTH
+                0x21         "STB_1176.2-99_BDH_OneSide"        OID_BDH_ONE_SIDE
+                0x22         "STB_1176.2-99_BDH_KeyTransport"   OID_BDH_KEY_KEY_TRANSPORT
+        0x01                 ""
+          0x81               ""
+            0xDB             ""
+              0x73           "gost28147"
+                0x0C         "gost28147-cfb"          OID_GOST28147_CFB
+                0x0D         "gost28147-ctr"          OID_GOST28147_CTR
+                0x0E         "gost28147-mac"          OID_GOST_MAC
+                0x03         ""
+                  0x01       "gost28147-sblock-1"
+    0x01                     ""
+      0x02                   "by-oac"
+        0x01                 "by-gov-pki"
+          0x01               "by-nces"
+            0x01             "by-gov-pki-ext"
+              0x03           "by-cert-policy"
+                0x02         ""
+                  0x02       ""                       OID_GOVPKI_CA2_TECHCERT
 0x2B                         ""
   0x06                       "dod"
     0x01                     "internet"
@@ -207,6 +324,9 @@
         0x01                 "enterprise"
           0x82               ""
             0x37             "Microsoft"
+              0x02           ""
+                0x01         ""
+                  0x0E       "msCertificateExtensions"  OID_MS_CERTIFICATE_EXTENSIONS
               0x0A           ""
                 0x03         ""
                   0x03       "msSGC"
@@ -242,6 +362,16 @@
                     0x04     "BLISS-with-SHA3-512"		OID_BLISS_WITH_SHA3_512
                     0x05     "BLISS-with-SHA3-384"		OID_BLISS_WITH_SHA3_384
                     0x06     "BLISS-with-SHA3-256"		OID_BLISS_WITH_SHA3_256
+            0xBB             ""
+              0x1A           "BUTB"
+                0x01         "BUTB-TradePermissions"
+                  0x01       "BUTB-VisitorPermission"
+                  0x02       "BUTB-BrokerPermission"
+                0x02         "BUTB-TradeSectionAccess"
+                  0x01       "BUTB-SectionMetall"
+                  0x02       "BUTB-SectionTimber"
+                  0x03       "BUTB-SectionAgri"
+                  0x04       "BUTB-SectionPPT"
           0x89               ""
             0x31             ""
               0x01           ""
@@ -292,6 +422,44 @@
                     0x30     "ees593ep1"
                     0x31     "ees743ep1"
                   0x03       "eess1-encodingMethods"
+          0xDE               ""
+            0x7C             "CONTACT"
+              0x01           ""
+                0x01         "STB_1176.1-99"            OID_HASH_STB1176
+                0x02         "STB_1176.2-99"            OID_EDS_STB1176
+                0x03         "CommonKeysAlgorithm"      OID_COMMON_KEYS_ALG
+              0x02           ""
+                0x01         ""
+                  0x01       "CertificateValidity"      OID_CERT_VALID
+                  0x03       "UserType"                 OID_USER_TYPE
+                  0x05       "PrivateKeyActivationTime" OID_PRIV_KEY_ACTIV_TIME
+                  0x06       "UserContactPrivileges"    OID_USER_CONTACT_PRIVILEGES
+                0x02         ""
+                  0x01       "Nick"                     OID_NICK
+                  0x02       "Procuration"
+                    0x01     "ProcurationType"
+                    0x02     "ProcurationNumber"
+                    0x03     "ProcurationIssueDate"
+                    0x04     "PrivilegesStartTime"
+                    0x05     "PrivilegesEndTime"
+                  0x05       "District"
+                  0x0B       "PostalAddress"
+                  0x0C       "PassportData"
+                  0x0D       "MilitaryCard"
+                  0x0E       "PensionCard"
+                  0x0F       "TradeUnionCard"
+                  0x10       "StudentCard" 
+                  0x11       "IdentityCard"             OID_IDENTITY_CARD
+                    0x01     "IdentityCardName" 
+                    0x02     "IdentityCardNumber"
+                    0x03     "IdentityCardIssueDate"
+                    0x04     "IdentityCardIssuedBy"
+          0xE2               ""
+            0x70             "Avest"
+              0x05           ""
+                0x03         "avest-IdentificationNumber"
+              0x68           ""
+                0x03         "avest-UNP"
       0x05                   "security"
         0x05                 "mechanisms"
           0x07               "id-pkix"
diff -ruN strongswan-5.8.4/src/libstrongswan/collections/linked_list.h strongswancont-5.8.4-svc/src/libstrongswan/collections/linked_list.h
--- strongswan-5.8.4/src/libstrongswan/collections/linked_list.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/collections/linked_list.h	2022-07-08 12:14:09.208653000 +0300
@@ -26,6 +26,7 @@
 typedef struct linked_list_t linked_list_t;
 
 #include <collections/enumerator.h>
+#include "../utils/utils/status.h"
 
 /**
  * Function to match elements in a linked list
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/builder.c strongswancont-5.8.4-svc/src/libstrongswan/credentials/builder.c
--- strongswan-5.8.4/src/libstrongswan/credentials/builder.c	2019-08-27 16:26:53.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/builder.c	2022-11-08 10:06:44.347773000 +0300
@@ -27,6 +27,7 @@
 	"BUILD_BLOB_SSHKEY",
 	"BUILD_BLOB_ALGID_PARAMS",
 	"BUILD_KEY_SIZE",
+	"BUILD_KEY_INITIAL_RANDOM",
 	"BUILD_SIGNING_KEY",
 	"BUILD_SIGNING_CERT",
 	"BUILD_PUBLIC_KEY",
@@ -73,6 +74,15 @@
 	"BUILD_SAFE_PRIMES",
 	"BUILD_SHARES",
 	"BUILD_THRESHOLD",
+	"BUILD_USBBAR_PASS",
+	"BUILD_USBBAR_PWD",
+	"BUILD_BPKI_PARAMS",
+	"BUILD_BLOB_STB1176_KEY",
+	"BUILD_BIGN_PUBLIC_FROM_PRIVATE",
+	"BUILD_BPKI_PKCS10",
+	"BUILD_CERT_VALIDITY",
+	"BUILD_POLICY_GOVPKI",
+	"BUILD_78_EXTS_REQUEST_OID",
 	"BUILD_EDDSA_PUB",
 	"BUILD_EDDSA_PRIV_ASN1_DER",
 	"BUILD_CRITICAL_EXTENSION",
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/builder.h strongswancont-5.8.4-svc/src/libstrongswan/credentials/builder.h
--- strongswan-5.8.4/src/libstrongswan/credentials/builder.h	2019-08-27 16:26:53.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/builder.h	2022-11-08 10:07:30.044812000 +0300
@@ -64,6 +64,10 @@
 	BUILD_BLOB_ALGID_PARAMS,
 	/** key size in bits, as used for key generation, u_int */
 	BUILD_KEY_SIZE,
+
+	/** Initial random data, as used for key generation, chunk_t */
+	BUILD_KEY_INITIAL_RANDOM,
+
 	/** private key to use for signing, private_key_t* */
 	BUILD_SIGNING_KEY,
 	/** certificate used for signing, certificate_t* */
@@ -156,6 +160,23 @@
 	BUILD_SHARES,
 	/** minimum number of participating private key shares */
 	BUILD_THRESHOLD,
+	/** usb barrier wraped password file path */
+	BUILD_USBBAR_PASS,
+	/** usb barrier password */
+	BUILD_USBBAR_PWD,
+
+	BUILD_BPKI_PARAMS,
+	/** */
+	BUILD_BLOB_CONTACT_KEY,
+	/** BIGN public key from private */ 
+	BUILD_BIGN_PUBLIC_FROM_PRIVATE,
+	/** BPKI PKCS#10 certificate request, bool */
+	BUILD_BPKI_PKCS10,
+
+	BUILD_CERT_VALIDITY,
+	BUILD_POLICY_GOVPKI,
+	BUILD_78_EXTS_REQUEST_OID,
+	
 	/** EdDSA public key blob */
 	BUILD_EDDSA_PUB,
 	/** DER encoded ASN.1 EdDSA private key */
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/certificates/x509.h strongswancont-5.8.4-svc/src/libstrongswan/credentials/certificates/x509.h
--- strongswan-5.8.4/src/libstrongswan/credentials/certificates/x509.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/certificates/x509.h	2022-07-06 15:47:34.770983000 +0300
@@ -33,6 +33,7 @@
 typedef struct x509_cdp_t x509_cdp_t;
 typedef enum x509_flag_t x509_flag_t;
 typedef enum x509_constraint_t x509_constraint_t;
+typedef enum x509_key_usage_t x509_key_usage_t;
 
 /**
  * X.509 certificate flags.
@@ -84,6 +85,23 @@
 };
 
 /**
+ * X.509 key usage flags
+ */
+enum x509_key_usage_t
+{
+	X509_KU_NONE =              0,
+	X509_KU_DIGITAL_SIGNATURE =	(1<<0),
+	X509_KU_NON_REPUDIATION =	(1<<1),
+	X509_KU_KEY_ENCIPHERMENT =	(1<<2),
+	X509_KU_DATA_ENCIPHERMENT =	(1<<3),
+	X509_KU_KEY_AGREEMENT =		(1<<4),
+	X509_KU_KEY_CERT_SIGN =		(1<<5),
+	X509_KU_CRL_SIGN =			(1<<6),
+	X509_KU_ENCIPHER_ONLY =		(1<<7),
+	X509_KU_DECIPHER_ONLY =		(1<<8),
+};
+
+/**
  * X.509 certPolicy extension.
  */
 struct x509_cert_policy_t {
@@ -136,6 +154,13 @@
 	x509_flag_t (*get_flags)(x509_t *this);
 
 	/**
+	 * Get key usage flags for this certifcate.
+	 * 
+	 * @return			set of flags
+	 */
+	x509_key_usage_t (*get_keyUsage)(x509_t *this);
+
+	/**
 	 * Get the certificate serial number.
 	 *
 	 * @return			chunk pointing to internal serial number
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/cred_encoding.h strongswancont-5.8.4-svc/src/libstrongswan/credentials/cred_encoding.h
--- strongswan-5.8.4/src/libstrongswan/credentials/cred_encoding.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/cred_encoding.h	2022-07-06 15:47:34.778983000 +0300
@@ -71,6 +71,8 @@
 	KEYID_PGPV3,
 	/** PGPv4 fingerprint */
 	KEYID_PGPV4,
+	/** BELT fingerprint over subjectPublicKey */
+	KEYID_PUBKEY_BELT,
 
 	KEYID_MAX,
 
@@ -99,6 +101,11 @@
 	/** PGP Packet encoded certificate */
 	CERT_PGP_PKT,
 
+	/** BIGN subjectPublicKeyInfo encoding */
+	PUBKEY_SPKI_BIGN_ASN1_DER,
+	/** subjectPublicKey encoding */
+	PUBKEY_SPK_ASN1_DER,
+
 	CRED_ENCODING_MAX,
 };
 
@@ -144,6 +151,8 @@
 	CRED_PART_PKCS10_ASN1_DER,
 	/** a PGP encoded certificate */
 	CRED_PART_PGP_CERT,
+	/** a raw key value */
+	CRED_PART_RAW_KEY,
 	/** a DER encoded EdDSA public key */
 	CRED_PART_EDDSA_PUB_ASN1_DER,
 	/** a DER encoded EdDSA private key */
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/credential_manager.c strongswancont-5.8.4-svc/src/libstrongswan/credentials/credential_manager.c
--- strongswan-5.8.4/src/libstrongswan/credentials/credential_manager.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/credential_manager.c	2023-05-24 18:37:36.643162000 +0300
@@ -555,7 +555,7 @@
  */
 static bool check_lifetime(private_credential_manager_t *this,
 						   certificate_t *cert, char *label,
-						   int pathlen, bool trusted, auth_cfg_t *auth)
+						   int pathlen, bool anchor, auth_cfg_t *auth)
 {
 	time_t not_before, not_after;
 	cert_validator_t *validator;
@@ -570,7 +570,7 @@
 			continue;
 		}
 		status = validator->check_lifetime(validator, cert,
-										   pathlen, trusted, auth);
+										   pathlen, anchor, auth);
 		if (status != NEED_MORE)
 		{
 			break;
@@ -603,13 +603,13 @@
  */
 static bool check_certificate(private_credential_manager_t *this,
 				certificate_t *subject, certificate_t *issuer, bool online,
-				int pathlen, bool trusted, auth_cfg_t *auth)
+				int pathlen, bool anchor, auth_cfg_t *auth)
 {
 	cert_validator_t *validator;
 	enumerator_t *enumerator;
 
 	if (!check_lifetime(this, subject, "subject", pathlen, FALSE, auth) ||
-		!check_lifetime(this, issuer, "issuer", pathlen + 1, trusted, auth))
+		!check_lifetime(this, issuer, "issuer", pathlen + 1, anchor, auth))
 	{
 		return FALSE;
 	}
@@ -622,7 +622,7 @@
 			continue;
 		}
 		if (!validator->validate(validator, subject, issuer,
-								 online, pathlen, trusted, auth))
+								 online, pathlen, anchor, auth))
 		{
 			enumerator->destroy(enumerator);
 			return FALSE;
@@ -725,6 +725,7 @@
 	auth_cfg_t *auth;
 	signature_params_t *scheme;
 	int pathlen;
+	bool is_anchor = FALSE;
 
 	auth = auth_cfg_create();
 	get_key_strength(subject, auth);
@@ -742,7 +743,7 @@
 				auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer));
 				DBG1(DBG_CFG, "  using trusted ca certificate \"%Y\"",
 							  issuer->get_subject(issuer));
-				trusted = TRUE;
+				trusted = is_anchor = TRUE;
 			}
 			else
 			{
@@ -777,11 +778,18 @@
 				DBG1(DBG_CFG, "  issuer is \"%Y\"",
 					 current->get_issuer(current));
 				call_hook(this, CRED_HOOK_NO_ISSUER, current);
+				if (trusted)
+				{
+					DBG1(DBG_CFG, "  reached end of incomplete trust chain for "
+						 "trusted certificate \"%Y\"",
+						 subject->get_subject(subject));
+				}
 				break;
 			}
 		}
-		if (!check_certificate(this, current, issuer, online,
-							   pathlen, trusted, auth))
+		/* don't do online verification here */
+		if (!check_certificate(this, current, issuer, FALSE,
+							   pathlen, is_anchor, auth))
 		{
 			trusted = FALSE;
 			issuer->destroy(issuer);
@@ -793,7 +801,7 @@
 		}
 		current->destroy(current);
 		current = issuer;
-		if (trusted)
+		if (is_anchor)
 		{
 			DBG1(DBG_CFG, "  reached self-signed root ca with a "
 				 "path length of %d", pathlen);
@@ -806,6 +814,34 @@
 		DBG1(DBG_CFG, "maximum path length of %d exceeded", MAX_TRUST_PATH_LEN);
 		call_hook(this, CRED_HOOK_EXCEEDED_PATH_LEN, subject);
 	}
+	else if (trusted && online)
+	{
+		enumerator_t *enumerator;
+		auth_rule_t rule;
+
+		/* do online revocation checks after basic validation of the chain */
+		pathlen = 0;
+		current = subject;
+		enumerator = auth->create_enumerator(auth);
+		while (enumerator->enumerate(enumerator, &rule, &issuer))
+		{
+			if (rule == AUTH_RULE_CA_CERT || rule == AUTH_RULE_IM_CERT)
+			{
+				if (!check_certificate(this, current, issuer, TRUE, pathlen++,
+									   rule == AUTH_RULE_CA_CERT, auth))
+				{
+					trusted = FALSE;
+					break;
+				}
+				else if (rule == AUTH_RULE_CA_CERT)
+				{
+					break;
+				}
+				current = issuer;
+			}
+		}
+		enumerator->destroy(enumerator);
+	}	
 	if (trusted)
 	{
 		result->merge(result, auth, FALSE);
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/keys/public_key.c strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/public_key.c
--- strongswan-5.8.4/src/libstrongswan/credentials/keys/public_key.c	2018-12-14 18:48:24.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/public_key.c	2023-04-30 13:34:32.646541000 +0300
@@ -20,17 +20,18 @@
 #include "public_key.h"
 #include "signature_params.h"
 
-ENUM(key_type_names, KEY_ANY, KEY_BLISS,
+ENUM(key_type_names, KEY_ANY, KEY_BIGN,
 	"ANY",
 	"RSA",
 	"ECDSA",
 	"DSA",
 	"ED25519",
 	"ED448",
-	"BLISS"
+	"BLISS",
+	"BIGN",
 );
 
-ENUM(signature_scheme_names, SIGN_UNKNOWN, SIGN_BLISS_WITH_SHA3_512,
+ENUM(signature_scheme_names, SIGN_UNKNOWN, SIGN_BIGN_WITH_HBELT,
 	"UNKNOWN",
 	"RSA_EMSA_PKCS1_NULL",
 	"RSA_EMSA_PKCS1_MD5",
@@ -60,6 +61,7 @@
 	"BLISS_WITH_SHA3_256",
 	"BLISS_WITH_SHA3_384",
 	"BLISS_WITH_SHA3_512",
+	"BIGN_WITH_HBELT",
 );
 
 ENUM(encryption_scheme_names, ENCRYPT_UNKNOWN, ENCRYPT_RSA_OAEP_SHA512,
@@ -176,6 +178,8 @@
 			return SIGN_BLISS_WITH_SHA3_384;
 		case OID_BLISS_WITH_SHA3_256:
 			return SIGN_BLISS_WITH_SHA3_256;
+		case OID_HASH_BELT:
+			return SIGN_BIGN_WITH_HBELT;
 	}
 	return SIGN_UNKNOWN;
 }
@@ -240,6 +244,8 @@
 			return OID_BLISS_WITH_SHA3_384;
 		case SIGN_BLISS_WITH_SHA3_512:
 			return OID_BLISS_WITH_SHA3_512;
+		case SIGN_BIGN_WITH_HBELT:
+			return OID_HASH_BELT;
 	}
 	return OID_UNKNOWN;
 }
@@ -376,6 +382,8 @@
 		case SIGN_BLISS_WITH_SHA3_384:
 		case SIGN_BLISS_WITH_SHA3_512:
 			return KEY_BLISS;
+		case SIGN_BIGN_WITH_HBELT:
+			return KEY_BIGN;
 	}
 	return KEY_ANY;
 }
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/keys/public_key.h strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/public_key.h
--- strongswan-5.8.4/src/libstrongswan/credentials/keys/public_key.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/public_key.h	2022-07-06 15:47:34.754983000 +0300
@@ -49,6 +49,8 @@
 	KEY_ED448   = 5,
 	/** BLISS */
 	KEY_BLISS = 6,
+	/** BIGN pub key */
+	KEY_BIGN = 7,
 };
 
 /**
@@ -122,6 +124,8 @@
 	SIGN_BLISS_WITH_SHA3_384,
 	/** BLISS with SHA-3_512                                           */
 	SIGN_BLISS_WITH_SHA3_512,
+	/** STB 34.101.45 signature with Belt-HASH 						   */
+	SIGN_BIGN_WITH_HBELT,
 };
 
 /**
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/keys/shared_key.c strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/shared_key.c
--- strongswan-5.8.4/src/libstrongswan/credentials/keys/shared_key.c	2018-10-23 20:03:28.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/shared_key.c	2023-06-12 15:58:29.299989000 +0300
@@ -77,7 +77,7 @@
 {
 	if (ref_put(&this->ref))
 	{
-		free(this->key.ptr);
+		chunk_clear(&this->key);
 		free(this);
 	}
 }
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/keys/signature_params.c strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/signature_params.c
--- strongswan-5.8.4/src/libstrongswan/credentials/keys/signature_params.c	2018-12-14 18:48:24.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/keys/signature_params.c	2022-07-06 15:47:34.778983000 +0300
@@ -322,7 +322,11 @@
 			case RSASSA_PSS_PARAMS_SALT_LEN:
 				if (object.len)
 				{
-					params->salt_len = (size_t)asn1_parse_integer_uint64(object);
+					params->salt_len = (ssize_t)asn1_parse_integer_uint64(object);
+					if (params->salt_len < 0)
+					{
+						goto end;
+					}
 				}
 				break;
 			case RSASSA_PSS_PARAMS_TRAILER:
diff -ruN strongswan-5.8.4/src/libstrongswan/credentials/sets/cert_cache.c strongswancont-5.8.4-svc/src/libstrongswan/credentials/sets/cert_cache.c
--- strongswan-5.8.4/src/libstrongswan/credentials/sets/cert_cache.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/credentials/sets/cert_cache.c	2023-03-23 12:40:31.012143000 +0300
@@ -151,7 +151,7 @@
 	for (try = 0; try < REPLACE_TRIES; try++)
 	{
 		/* replace a random relation */
-		offset = random();
+		offset = random() % CACHE_SIZE;
 		for (i = 0; i < CACHE_SIZE; i++)
 		{
 			rel = &this->relations[(i + offset) % CACHE_SIZE];
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/crypters/crypter.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypters/crypter.c
--- strongswan-5.8.4/src/libstrongswan/crypto/crypters/crypter.c	2019-11-28 23:30:39.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypters/crypter.c	2022-07-06 15:47:34.806984000 +0300
@@ -47,14 +47,26 @@
 	"CAMELLIA_CCM_12",
 	"CAMELLIA_CCM_16",
 	"CHACHA20_POLY1305");
-ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_AES_ECB, ENCR_CHACHA20_POLY1305,
+ENUM_NEXT(encryption_algorithm_names, ENCR_GOST28147_CFB_LEGACY, ENCR_BELT_CTR_LEGACY, ENCR_CHACHA20_POLY1305,
+	"GOST28147_CFB_LEGACY",
+	"BELT_CBC_LEGACY",
+	"BELT_CFB_LEGACY",
+	"BELT_CTR_LEGACY");
+ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_AES_ECB, ENCR_BELT_CTR_LEGACY,
 	"UNDEFINED",
 	"DES_ECB",
 	"SERPENT_CBC",
 	"TWOFISH_CBC",
 	"RC2_CBC",
 	"AES_ECB");
-ENUM_END(encryption_algorithm_names, ENCR_AES_ECB);
+ENUM_NEXT(encryption_algorithm_names, ENCR_GOST28147_CTR, ENCR_GOST28147_CTR_LEGACY, ENCR_AES_ECB,
+	"GOST28147_CTR",
+	"GOST28147_CFB",
+	"BELT_CBC",
+	"BELT_CFB",
+	"BELT_CTR",
+	"GOST28147_CTR_LEGACY");
+ENUM_END(encryption_algorithm_names, ENCR_GOST28147_CTR_LEGACY);
 
 /*
  * Described in header.
@@ -98,6 +110,26 @@
 			alg = ENCR_CAMELLIA_CBC;
 			alg_key_size = 256;
 			break;
+		case OID_GOST28147_CTR:
+			alg = ENCR_GOST28147_CTR;
+			alg_key_size = 256;
+			break;
+		case OID_GOST28147_CFB:
+			alg = ENCR_GOST28147_CFB;
+			alg_key_size = 256;
+			break;
+		case OID_BELT_CBC:
+			alg = ENCR_BELT_CBC;
+			alg_key_size = 256;
+			break;		
+		case OID_BELT_CFB:
+			alg = ENCR_BELT_CFB;
+			alg_key_size = 256;
+			break;		
+		case OID_BELT_CTR:
+			alg = ENCR_BELT_CTR;
+			alg_key_size = 256;
+			break;		
 		case OID_BLOWFISH_CBC:
 			alg = ENCR_BLOWFISH;
 			alg_key_size = 0;
@@ -160,6 +192,26 @@
 					oid = OID_UNKNOWN;
 			}
 			break;
+		case ENCR_GOST28147_CTR_LEGACY:
+		case ENCR_GOST28147_CTR:
+			oid = OID_GOST28147_CTR;
+			break;
+		case ENCR_GOST28147_CFB_LEGACY:
+		case ENCR_GOST28147_CFB:
+			oid = OID_GOST28147_CFB;
+			break;
+		case ENCR_BELT_CBC_LEGACY:
+		case ENCR_BELT_CBC:
+			oid = OID_BELT_CBC;
+			break;
+		case ENCR_BELT_CFB_LEGACY:
+		case ENCR_BELT_CFB:
+			oid = OID_BELT_CFB;
+			break;
+		case ENCR_BELT_CTR_LEGACY:
+		case ENCR_BELT_CTR:
+			oid = OID_BELT_CTR;
+			break;
 		case ENCR_BLOWFISH:
 			oid = OID_BLOWFISH_CBC;
 			break;
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/crypters/crypter.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypters/crypter.h
--- strongswan-5.8.4/src/libstrongswan/crypto/crypters/crypter.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypters/crypter.h	2022-07-06 15:47:34.802984000 +0300
@@ -58,6 +58,11 @@
 	ENCR_CAMELLIA_CCM_ICV12 = 26,
 	ENCR_CAMELLIA_CCM_ICV16 = 27,
 	ENCR_CHACHA20_POLY1305 =  28,
+	
+	ENCR_GOST28147_CFB_LEGACY = 29,
+	ENCR_BELT_CBC_LEGACY =      30,
+	ENCR_BELT_CFB_LEGACY =      31,
+	ENCR_BELT_CTR_LEGACY =      32,
 	ENCR_UNDEFINED =        1024,
 	ENCR_DES_ECB =          1025,
 	ENCR_SERPENT_CBC =      1026,
@@ -65,6 +70,14 @@
 	/* see macros below to handle RC2 (effective) key length */
 	ENCR_RC2_CBC =          1028,
 	ENCR_AES_ECB =			1029,
+	/* BAS */
+	ENCR_GOST28147_CTR =   65530,
+	ENCR_GOST28147_CFB =   65531,
+	ENCR_BELT_CBC =        65532,
+	ENCR_BELT_CFB =        65533,
+	ENCR_BELT_CTR =        65534,
+
+	ENCR_GOST28147_CTR_LEGACY = 65535,
 };
 
 #define DES_BLOCK_SIZE			 8
@@ -73,6 +86,9 @@
 #define CAMELLIA_BLOCK_SIZE		16
 #define SERPENT_BLOCK_SIZE		16
 #define TWOFISH_BLOCK_SIZE		16
+#define GOST_BLOCK_SIZE 		 8
+#define BELT_BLOCK_SIZE 	    16
+#define BELT_IV_SIZE			16
 
 /**
  * For RC2, if the effective key size in bits is not key_size * 8, it should
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/crypto_factory.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypto_factory.c
--- strongswan-5.8.4/src/libstrongswan/crypto/crypto_factory.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypto_factory.c	2023-02-10 16:27:09.793827000 +0300
@@ -57,6 +57,7 @@
 		rng_constructor_t create_rng;
 		nonce_gen_constructor_t create_nonce_gen;
 		dh_constructor_t create_dh;
+		key_tfmer_constructor_t create_key_tfmer;
 		void *create;
 	};
 };
@@ -124,6 +125,11 @@
 	linked_list_t *dhs;
 
 	/**
+	 * registered key transformers, as entry_t
+	 */
+	linked_list_t *transformers;
+
+	/**
 	 * test manager to test crypto algorithms
 	 */
 	crypto_tester_t *tester;
@@ -478,6 +484,32 @@
 	return diffie_hellman;
 }
 
+METHOD(crypto_factory_t, create_key_transformer, key_transformer_t*,
+	private_crypto_factory_t* this, key_transform_alorithm_t algo)
+{
+	enumerator_t *enumerator;
+	entry_t *entry;
+	key_transformer_t *key_transformer = NULL;
+
+	this->lock->read_lock(this->lock);
+	enumerator = this->transformers->create_enumerator(this->transformers);
+	while (enumerator->enumerate(enumerator, &entry))
+	{
+		if (entry->algo == algo)
+		{
+			key_transformer = entry->create_key_tfmer(algo);
+			if (key_transformer)
+			{
+				break;
+			}
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
+
+	return key_transformer;
+}
+
 /**
  * Insert an algorithm entry to a list
  *
@@ -888,6 +920,34 @@
 	this->lock->unlock(this->lock);
 }
 
+METHOD(crypto_factory_t, add_key_transformer, bool,
+	private_crypto_factory_t *this, key_transform_alorithm_t algo,
+	const char *plugin_name, key_tfmer_constructor_t create)
+{
+	add_entry(this, this->transformers, algo, plugin_name, 0, create);
+	return TRUE;
+}
+
+METHOD(crypto_factory_t, remove_key_transformer, void,
+	private_crypto_factory_t *this, key_tfmer_constructor_t create)
+{
+	entry_t *entry;
+	enumerator_t *enumerator;
+
+	this->lock->write_lock(this->lock);
+	enumerator = this->transformers->create_enumerator(this->transformers);
+	while (enumerator->enumerate(enumerator, &entry))
+	{
+		if (entry->create_key_tfmer == create)
+		{
+			this->transformers->remove_at(this->transformers, enumerator);
+			free(entry);
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
+}
+
 CALLBACK(entry_match, bool,
 	entry_t *a, va_list args)
 {
@@ -1152,6 +1212,34 @@
 	return create_enumerator(this, this->nonce_gens, nonce_gen_filter);
 }
 
+/**
+ * Filter function to enumerate algorithm, not entry
+ */
+CALLBACK(key_transformer_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
+{
+	entry_t *entry;
+	key_transform_alorithm_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+METHOD(crypto_factory_t, create_key_transformer_enumerator, enumerator_t*,
+	private_crypto_factory_t *this)
+{
+	return create_enumerator(this, this->transformers, key_transformer_filter);
+}
+
+
 METHOD(crypto_factory_t, add_test_vector, void,
 	private_crypto_factory_t *this, transform_type_t type, void *vector)
 {
@@ -1327,6 +1415,7 @@
 	this->rngs->destroy(this->rngs);
 	this->nonce_gens->destroy(this->nonce_gens);
 	this->dhs->destroy(this->dhs);
+	this->transformers->destroy(this->transformers);
 	this->tester->destroy(this->tester);
 	this->lock->destroy(this->lock);
 	free(this);
@@ -1351,6 +1440,7 @@
 			.create_rng = _create_rng,
 			.create_nonce_gen = _create_nonce_gen,
 			.create_dh = _create_dh,
+			.create_key_transformer = _create_key_transformer,
 			.add_crypter = _add_crypter,
 			.remove_crypter = _remove_crypter,
 			.add_aead = _add_aead,
@@ -1371,6 +1461,8 @@
 			.remove_nonce_gen = _remove_nonce_gen,
 			.add_dh = _add_dh,
 			.remove_dh = _remove_dh,
+			.add_key_transformer = _add_key_transformer,
+			.remove_key_transformer = _remove_key_transformer,
 			.create_crypter_enumerator = _create_crypter_enumerator,
 			.create_aead_enumerator = _create_aead_enumerator,
 			.create_signer_enumerator = _create_signer_enumerator,
@@ -1381,6 +1473,7 @@
 			.create_dh_enumerator = _create_dh_enumerator,
 			.create_rng_enumerator = _create_rng_enumerator,
 			.create_nonce_gen_enumerator = _create_nonce_gen_enumerator,
+			.create_key_transformer_enumerator = _create_key_transformer_enumerator,
 			.add_test_vector = _add_test_vector,
 			.create_verify_enumerator = _create_verify_enumerator,
 			.destroy = _destroy,
@@ -1395,6 +1488,7 @@
 		.rngs = linked_list_create(),
 		.nonce_gens = linked_list_create(),
 		.dhs = linked_list_create(),
+		.transformers = linked_list_create(),
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
 		.tester = crypto_tester_create(),
 		.test_on_add = lib->settings->get_bool(lib->settings,
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/crypto_factory.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypto_factory.h
--- strongswan-5.8.4/src/libstrongswan/crypto/crypto_factory.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypto_factory.h	2022-07-06 15:47:34.810984000 +0300
@@ -36,6 +36,7 @@
 #include <crypto/drbgs/drbg.h>
 #include <crypto/nonce_gen.h>
 #include <crypto/diffie_hellman.h>
+#include <crypto/key_transformer.h>
 #include <crypto/transform.h>
 
 #define CRYPTO_MAX_ALG_LINE          120   /* characters */
@@ -95,6 +96,11 @@
 typedef diffie_hellman_t* (*dh_constructor_t)(diffie_hellman_group_t group, ...);
 
 /**
+ * Constructor function for key transformer
+ */
+typedef key_transformer_t* (*key_tfmer_constructor_t)(key_transform_alorithm_t algo);
+
+/**
  * Handles crypto modules and creates instances.
  */
 struct crypto_factory_t {
@@ -194,6 +200,15 @@
 								   diffie_hellman_group_t group, ...);
 
 	/**
+	 * Create a key transformer instance.
+	 *
+	 * @param algo 			key transform algorithm to use
+	 * @return 				key_transformer_t instance, NULL if not supported
+	 */
+	key_transformer_t* (*create_key_transformer)(crypto_factory_t *this, 
+											key_transform_alorithm_t algo);
+
+	/**
 	 * Register a crypter constructor.
 	 *
 	 * @param algo			algorithm to constructor
@@ -378,6 +393,27 @@
 	void (*remove_dh)(crypto_factory_t *this, dh_constructor_t create);
 
 	/**
+	 * Register key transformer constructor.
+	 *
+	 * @param algo			algorithm to constructor
+	 * @param plugin_name	plugin that registered this algorithm
+	 * @param create		constructor function for that algorithm
+	 * @return				TRUE if registered, FALSE if test vector failed
+	 */
+	bool (*add_key_transformer)(crypto_factory_t *this,
+								key_transform_alorithm_t algo, 
+								const char *plugin_name,
+								key_tfmer_constructor_t create);
+
+	/**
+	 * Unregister key transformer constructor.
+	 *
+	 * @param create		constructor function to unregiste
+	 */
+	void (*remove_key_transformer)(crypto_factory_t *this,
+								key_tfmer_constructor_t create);
+
+	/**
 	 * Create an enumerator over all registered crypter algorithms.
 	 *
 	 * @return				enumerator over encryption_algorithm_t, plugin
@@ -448,6 +484,13 @@
 	enumerator_t* (*create_nonce_gen_enumerator)(crypto_factory_t *this);
 
 	/**
+	 * Create an enumerator over all registered key transformers.
+	 *
+	 * @return				enumerator over key_transform_alorithm_t, plugin
+	 */
+	enumerator_t* (*create_key_transformer_enumerator)(crypto_factory_t *this);
+
+	/**
 	 * Add a test vector to the crypto factory.
 	 *
 	 * @param type			type of the test vector
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/crypto_tester.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypto_tester.c
--- strongswan-5.8.4/src/libstrongswan/crypto/crypto_tester.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/crypto_tester.c	2023-05-15 14:47:42.540788000 +0300
@@ -287,7 +287,7 @@
 		}
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 encryption_algorithm_names, alg, plugin_name, get_name(vector));
 			break;
 		}
@@ -297,13 +297,13 @@
 	{
 		if (failed)
 		{
-			DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
+			DBG2(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
 				 encryption_algorithm_names, alg, plugin_name, key_size);
 			return FALSE;
 		}
 		else
 		{
-			DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+			DBG2(DBG_LIB, "%s %N[%s]: no test vectors found",
 				 this->required ? "disabled" : "enabled ",
 				 encryption_algorithm_names, alg, plugin_name);
 			return !this->required;
@@ -314,13 +314,13 @@
 		if (speed)
 		{
 			*speed = bench_crypter(this, alg, create, key_size);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points "
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points "
 				 "(%zd bit key)", encryption_algorithm_names, alg,
 				 plugin_name, tested, *speed, key_size * 8);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 encryption_algorithm_names, alg, plugin_name, tested);
 		}
 	}
@@ -417,7 +417,7 @@
 		aead = create(alg, vector->key_size, vector->salt_size);
 		if (!aead)
 		{
-			DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
+			DBG2(DBG_LIB, "%N[%s]: %u bit key size not supported",
 				 encryption_algorithm_names, alg, plugin_name,
 				 BITS_PER_BYTE * vector->key_size);
 			continue;
@@ -482,7 +482,7 @@
 		}
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 encryption_algorithm_names, alg, plugin_name, get_name(vector));
 			break;
 		}
@@ -492,13 +492,13 @@
 	{
 		if (failed)
 		{
-			DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
+			DBG2(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
 				 encryption_algorithm_names, alg, plugin_name, key_size);
 			return FALSE;
 		}
 		else
 		{
-			DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+			DBG2(DBG_LIB, "%s %N[%s]: no test vectors found",
 				 this->required ? "disabled" : "enabled ",
 				 encryption_algorithm_names, alg, plugin_name);
 			return !this->required;
@@ -509,13 +509,13 @@
 		if (speed)
 		{
 			*speed = bench_aead(this, alg, create, key_size);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points "
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points "
 				 "(%zd bit key)", encryption_algorithm_names, alg,
 				 plugin_name, tested, *speed, key_size * 8);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 encryption_algorithm_names, alg, plugin_name, tested);
 		}
 	}
@@ -594,7 +594,7 @@
 		signer = create(alg);
 		if (!signer)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: creating instance failed",
 				 integrity_algorithm_names, alg, plugin_name);
 			break;
 		}
@@ -674,7 +674,7 @@
 		chunk_free(&mac);
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 integrity_algorithm_names, alg, plugin_name, get_name(vector));
 			break;
 		}
@@ -682,7 +682,7 @@
 	enumerator->destroy(enumerator);
 	if (!tested)
 	{
-		DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+		DBG2(DBG_LIB, "%s %N[%s]: no test vectors found",
 			 this->required ? "disabled" : "enabled ",
 			 integrity_algorithm_names, alg, plugin_name);
 		return !this->required;
@@ -692,12 +692,12 @@
 		if (speed)
 		{
 			*speed = bench_signer(this, alg, create);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
 				 integrity_algorithm_names, alg, plugin_name, tested, *speed);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 integrity_algorithm_names, alg, plugin_name, tested);
 		}
 	}
@@ -765,7 +765,7 @@
 		hasher = create(alg);
 		if (!hasher)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: creating instance failed",
 				 hash_algorithm_names, alg, plugin_name);
 			break;
 		}
@@ -830,7 +830,7 @@
 		chunk_free(&hash);
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 hash_algorithm_names, alg, plugin_name, get_name(vector));
 			break;
 		}
@@ -838,7 +838,7 @@
 	enumerator->destroy(enumerator);
 	if (!tested)
 	{
-		DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+		DBG2(DBG_LIB, "%s %N[%s]: no test vectors found",
 			 this->required ? "disabled" : "enabled ",
 			 hash_algorithm_names, alg, plugin_name);
 		return !this->required;
@@ -848,12 +848,12 @@
 		if (speed)
 		{
 			*speed = bench_hasher(this, alg, create);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
 				 hash_algorithm_names, alg, plugin_name, tested, *speed);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 hash_algorithm_names, alg, plugin_name, tested);
 		}
 	}
@@ -928,7 +928,7 @@
 		prf = create(alg);
 		if (!prf)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: creating instance failed",
 				 pseudo_random_function_names, alg, plugin_name);
 			break;
 		}
@@ -1016,7 +1016,7 @@
 		chunk_free(&out);
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 pseudo_random_function_names, alg, plugin_name, get_name(vector));
 			break;
 		}
@@ -1024,7 +1024,7 @@
 	enumerator->destroy(enumerator);
 	if (!tested)
 	{
-		DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+		DBG2(DBG_LIB, "%s %N[%s]: no test vectors found",
 			 this->required ? "disabled" : "enabled ",
 			 pseudo_random_function_names, alg, plugin_name);
 		return !this->required;
@@ -1034,12 +1034,12 @@
 		if (speed)
 		{
 			*speed = bench_prf(this, alg, create);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
 				 pseudo_random_function_names, alg, plugin_name, tested, *speed);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 pseudo_random_function_names, alg, plugin_name, tested);
 		}
 	}
@@ -1110,7 +1110,7 @@
 		xof = create(alg);
 		if (!xof)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: creating instance failed",
 				 ext_out_function_names, alg, plugin_name);
 			break;
 		}
@@ -1156,7 +1156,7 @@
 		chunk_free(&out);
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 ext_out_function_names, alg, plugin_name, get_name(vector));
 			break;
 		}
@@ -1164,7 +1164,7 @@
 	enumerator->destroy(enumerator);
 	if (!tested)
 	{
-		DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+		DBG2(DBG_LIB, "%s %N[%s]: no test vectors found",
 			 this->required ? "disabled" : "enabled ",
 			 ext_out_function_names, alg, plugin_name);
 		return !this->required;
@@ -1174,12 +1174,12 @@
 		if (speed)
 		{
 			*speed = bench_xof(this, alg, create);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
 				 ext_out_function_names, alg, plugin_name, tested, *speed);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 ext_out_function_names, alg, plugin_name, tested);
 		}
 	}
@@ -1253,7 +1253,7 @@
 					  vector->personalization_str);
 		if (!drbg)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: creating instance failed",
 				 drbg_type_names, type, plugin_name);
 			entropy->destroy(entropy);
 			chunk_free(&out);
@@ -1282,7 +1282,7 @@
 		chunk_free(&out);
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 drbg_type_names, type, plugin_name, get_name(vector));
 			break;
 		}
@@ -1290,7 +1290,7 @@
 	enumerator->destroy(enumerator);
 	if (!tested)
 	{
-		DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
+		DBG2(DBG_LIB, "%s %N[%s]: no test vectors found",
 			 this->required ? "disabled" : "enabled ",
 			 drbg_type_names, type, plugin_name);
 		return !this->required;
@@ -1300,12 +1300,12 @@
 		if (speed)
 		{
 			*speed = bench_drbg(this, type, create);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
 				 drbg_type_names, type, plugin_name, tested, *speed);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 drbg_type_names, type, plugin_name, tested);
 		}
 	}
@@ -1499,7 +1499,7 @@
 			DESTROY_IF(b);
 			failed = TRUE;
 			tested++;
-			DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: creating instance failed",
 				 diffie_hellman_group_names, group, plugin_name);
 			break;
 		}
@@ -1556,7 +1556,7 @@
 		chunk_free(&bsec);
 		if (failed)
 		{
-			DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+			DBG2(DBG_LIB, "disabled %N[%s]: %s test vector failed",
 				 diffie_hellman_group_names, group, plugin_name, get_name(v));
 			break;
 		}
@@ -1564,7 +1564,7 @@
 	enumerator->destroy(enumerator);
 	if (!tested)
 	{
-		DBG1(DBG_LIB, "%s %N[%s]: no test vectors found / untestable",
+		DBG2(DBG_LIB, "%s %N[%s]: no test vectors found / untestable",
 			 this->required ? "disabled" : "enabled ",
 			 diffie_hellman_group_names, group, plugin_name);
 		return !this->required;
@@ -1574,12 +1574,12 @@
 		if (speed)
 		{
 			*speed = bench_dh(this, group, create);
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
 				 diffie_hellman_group_names, group, plugin_name, tested, *speed);
 		}
 		else
 		{
-			DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
+			DBG2(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
 				 diffie_hellman_group_names, group, plugin_name, tested);
 		}
 	}
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/diffie_hellman.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/diffie_hellman.c
--- strongswan-5.8.4/src/libstrongswan/crypto/diffie_hellman.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/diffie_hellman.c	2022-07-06 15:47:34.802984000 +0300
@@ -53,11 +53,12 @@
 	"NTRU_256");
 ENUM_NEXT(diffie_hellman_group_names, NH_128_BIT, NH_128_BIT, NTRU_256_BIT,
 	"NEWHOPE_128");
-ENUM_NEXT(diffie_hellman_group_names, MODP_CUSTOM, MODP_CUSTOM, NH_128_BIT,
+ENUM_NEXT(diffie_hellman_group_names, ECP_256_BIGN, ECP_256_BIGN, NH_128_BIT,
+	"ECP_256_BIGN");
+ENUM_NEXT(diffie_hellman_group_names, MODP_CUSTOM, MODP_CUSTOM, ECP_256_BIGN,
 	"MODP_CUSTOM");
 ENUM_END(diffie_hellman_group_names, MODP_CUSTOM);
 
-
 /**
  * List of known diffie hellman group parameters.
  */
@@ -493,6 +494,7 @@
 		case ECP_256_BP:
 		case ECP_384_BP:
 		case ECP_512_BP:
+		case ECP_256_BIGN:
 			return TRUE;
 		default:
 			return FALSE;
@@ -526,6 +528,9 @@
 				valid = value.len == params->prime.len;
 			}
 			break;
+		//case ECP_256_BIGN:
+		//	valid = value.len == 64;
+		//	break;
 		case ECP_192_BIT:
 			valid = value.len == 48;
 			break;
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/diffie_hellman.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/diffie_hellman.h
--- strongswan-5.8.4/src/libstrongswan/crypto/diffie_hellman.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/diffie_hellman.h	2022-07-06 15:47:34.790983000 +0300
@@ -72,6 +72,7 @@
 	NTRU_192_BIT = 1032,
 	NTRU_256_BIT = 1033,
 	NH_128_BIT   = 1040,
+	ECP_256_BIGN = 65201,
 	/** internally used DH group with additional parameters g and p, outside
 	 * of PRIVATE USE (i.e. IKEv2 DH group range) so it can't be negotiated */
 	MODP_CUSTOM = 65536,
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/hashers/hasher.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/hashers/hasher.c
--- strongswan-5.8.4/src/libstrongswan/crypto/hashers/hasher.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/hashers/hasher.c	2022-07-06 15:47:34.810984000 +0300
@@ -37,7 +37,9 @@
 	"HASH_SHA3_256",
 	"HASH_SHA3_384",
 	"HASH_SHA3_512");
-ENUM_END(hash_algorithm_names, HASH_SHA3_512);
+ENUM_NEXT(hash_algorithm_names, BELT_HASH, BELT_HASH, HASH_SHA3_512,
+	"BELT_HASH");
+ENUM_END(hash_algorithm_names, BELT_HASH);
 
 ENUM_BEGIN(hash_algorithm_short_names, HASH_SHA1, HASH_IDENTITY,
 	"sha1",
@@ -55,7 +57,9 @@
 	"sha3_256",
 	"sha3_384",
 	"sha3_512");
-ENUM_END(hash_algorithm_short_names, HASH_SHA3_512);
+ENUM_NEXT(hash_algorithm_short_names, BELT_HASH, BELT_HASH, HASH_SHA3_512,
+	"belt_hash");
+ENUM_END(hash_algorithm_short_names, BELT_HASH);
 
 ENUM_BEGIN(hash_algorithm_short_names_upper, HASH_SHA1, HASH_IDENTITY,
 	"SHA1",
@@ -73,7 +77,9 @@
 	"SHA3_256",
 	"SHA3_384",
 	"SHA3_512");
-ENUM_END(hash_algorithm_short_names_upper, HASH_SHA3_512);
+ENUM_NEXT(hash_algorithm_short_names_upper, BELT_HASH, BELT_HASH, HASH_SHA3_512,
+	"BELT_HASH");
+ENUM_END(hash_algorithm_short_names_upper, BELT_HASH);
 
 /*
  * Described in header
@@ -141,6 +147,8 @@
 		case OID_SHA512:
 		case OID_SHA512_WITH_RSA:
 			return HASH_SHA512;
+		case OID_BELT_HASH:
+			return BELT_HASH;
 		case OID_SHA3_224:
 		case OID_RSASSA_PKCS1V15_WITH_SHA3_224:
 			return HASH_SHA3_224;
@@ -180,12 +188,16 @@
 			return HASH_SHA384;
 		case PRF_HMAC_SHA2_512:
 			return HASH_SHA512;
+		case PRF_HMAC_HBELT:
+			return BELT_HASH;
 		case PRF_HMAC_TIGER:
 		case PRF_AES128_XCBC:
 		case PRF_AES128_CMAC:
 		case PRF_FIPS_DES:
 		case PRF_CAMELLIA128_XCBC:
 		case PRF_UNDEFINED:
+		case PRF_BRNG_CTR_HBELT:
+		case PRF_BRNG_HMAC_HBELT:
 			break;
 	}
 	return HASH_UNKNOWN;
@@ -227,6 +239,15 @@
 			case AUTH_HMAC_SHA2_512_512:
 				*length = 64;
 				break;
+			case AUTH_BELT_HASH_LEGACY:
+			case AUTH_GOST_MAC_LEGACY:
+			case AUTH_BELT_MAC_LEGACY:
+			case AUTH_BELT_HMAC_LEGACY:
+			case AUTH_BELT_HASH:
+			case AUTH_GOST_MAC:
+			case AUTH_BELT_MAC:
+			case AUTH_BELT_HMAC:
+				*length = 32;
 			default:
 				break;
 		}
@@ -251,6 +272,15 @@
 		case AUTH_HMAC_SHA2_512_256:
 		case AUTH_HMAC_SHA2_512_512:
 			return HASH_SHA512;
+		case AUTH_GOST_MAC_LEGACY:
+		case AUTH_BELT_MAC_LEGACY:
+		case AUTH_BELT_HMAC_LEGACY:
+		case AUTH_BELT_HASH_LEGACY:
+		case AUTH_GOST_MAC:
+		case AUTH_BELT_MAC:
+		case AUTH_BELT_HMAC:
+		case AUTH_BELT_HASH:
+			return BELT_HASH;		
 		case AUTH_AES_CMAC_96:
 		case AUTH_AES_128_GMAC:
 		case AUTH_AES_192_GMAC:
@@ -322,6 +352,8 @@
 					return AUTH_HMAC_SHA2_512_512;
 			}
 			break;
+		case BELT_HASH:
+			return AUTH_BELT_HASH;
 		case HASH_MD2:
 		case HASH_MD4:
 		case HASH_SHA224:
@@ -347,6 +379,7 @@
 		case HASH_SHA256:
 		case HASH_SHA384:
 		case HASH_SHA512:
+		case BELT_HASH:
 			return TRUE;
 		case HASH_UNKNOWN:
 		case HASH_MD2:
@@ -393,6 +426,9 @@
 		case HASH_SHA512:
 			oid = OID_SHA512;
 			break;
+		case BELT_HASH:
+			oid = OID_BELT_HASH;
+			break;
 		case HASH_SHA3_224:
 			oid = OID_SHA3_224;
 			break;
@@ -494,6 +530,15 @@
 				default:
 					return OID_UNKNOWN;
 			}
+		case KEY_BIGN:
+			switch (alg)
+			{
+				case BELT_HASH:
+					return OID_HASH_BELT;
+				case HASH_UNKNOWN:
+				default:
+					return OID_UNKNOWN;
+			}
 		default:
 			return OID_UNKNOWN;
 	}
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/hashers/hasher.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/hashers/hasher.h
--- strongswan-5.8.4/src/libstrongswan/crypto/hashers/hasher.h	2018-10-23 20:03:28.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/hashers/hasher.h	2022-07-06 15:47:34.802984000 +0300
@@ -42,6 +42,8 @@
 	HASH_SHA512			= 4,
 	/* RFC 8420 */
 	HASH_IDENTITY		= 5,
+
+	BELT_HASH			= 9,
 	/* use private use range for algorithms not defined/permitted by RFC 7427 */
 	HASH_UNKNOWN 		= 1024,
 	HASH_MD2 			= 1025,
@@ -62,6 +64,7 @@
 #define HASH_SIZE_SHA256	32
 #define HASH_SIZE_SHA384	48
 #define HASH_SIZE_SHA512	64
+#define HASH_SIZE_BELT		32
 
 /**
  * enum names for hash_algorithm_t.
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/iv/iv_gen.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/iv/iv_gen.c
--- strongswan-5.8.4/src/libstrongswan/crypto/iv/iv_gen.c	2019-11-28 23:30:39.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/iv/iv_gen.c	2022-07-06 15:47:34.802984000 +0300
@@ -40,6 +40,16 @@
 		case ENCR_SERPENT_CBC:
 		case ENCR_TWOFISH_CBC:
 		case ENCR_RC2_CBC:
+		case ENCR_GOST28147_CTR_LEGACY:
+		case ENCR_GOST28147_CFB_LEGACY:
+		case ENCR_BELT_CBC_LEGACY:
+		case ENCR_BELT_CFB_LEGACY:
+		case ENCR_BELT_CTR_LEGACY:
+		case ENCR_GOST28147_CTR:
+		case ENCR_GOST28147_CFB:
+		case ENCR_BELT_CBC:
+		case ENCR_BELT_CFB:
+		case ENCR_BELT_CTR:
 			return iv_gen_rand_create();
 		case ENCR_AES_CTR:
 		case ENCR_AES_CCM_ICV8:
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/key_transformer.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/key_transformer.c
--- strongswan-5.8.4/src/libstrongswan/crypto/key_transformer.c	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/key_transformer.c	2022-07-06 15:47:34.838984000 +0300
@@ -0,0 +1,6 @@
+#include "key_transformer.h"
+
+ENUM(key_transform_algorithm_names, KEYTFM_UNDEFINED, BELT_KEYREP_TRANSFORM,
+	"KEY_TRANSFORM_UNDEFINED",
+	"BELT_KEYREP_TRANSFORM",
+);
\ В конце файла нет новой строки
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/key_transformer.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/key_transformer.h
--- strongswan-5.8.4/src/libstrongswan/crypto/key_transformer.h	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/key_transformer.h	2022-07-06 15:47:34.830984000 +0300
@@ -0,0 +1,55 @@
+/**
+ * @defgroup key_transformer key_transformer
+ * @{ @ingroup crypto
+ */
+
+#ifndef KEY_TRANSFORMER_H_
+#define KEY_TRANSFORMER_H_
+
+typedef enum key_transform_alorithm_t key_transform_alorithm_t;
+typedef enum key_transform_args_t key_transform_args_t;
+typedef struct key_transformer_t key_transformer_t;
+
+#include <library.h>
+
+/**
+ *	Key transform algorithm
+ */
+enum key_transform_alorithm_t {
+
+	KEYTFM_UNDEFINED = 0,
+	
+	/** KeyRep algorithm from STB 34.101.31 */
+	BELT_KEYREP_TRANSFORM = 1,
+};
+
+/**
+ * enum strings for key_transform_alorithm_t.
+ */
+extern enum_name_t *key_transform_algorithm_names;
+
+/**
+ * Key transform interface.
+ */
+struct key_transformer_t {
+
+	/**
+	 * Transform key of proveded level into another key 
+	 * of level + 1 associated with proveded header.
+	 *
+	 * @param in 			a key to transform
+	 * @param out 			transformed key
+	 * @param in_level		level of the input key
+	 * @param out_header	header associated with produced key
+	 * @return				TRUE on successful transformation, FALSE otherwise
+	 */
+	bool (*transform)(key_transformer_t *this, chunk_t in, chunk_t out, 
+									chunk_t in_level, chunk_t out_header);
+
+	/**
+	 * Destructor.
+	 */
+	void (*destroy)(key_transformer_t *this);
+};
+
+#endif /** KEY_TRANSFORMER_H_ @}*/
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/prfs/prf.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/prfs/prf.c
--- strongswan-5.8.4/src/libstrongswan/crypto/prfs/prf.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/prfs/prf.c	2022-07-06 15:47:34.806984000 +0300
@@ -25,7 +25,7 @@
 	"PRF_FIPS_DES",
 	"PRF_KEYED_SHA1",
 	"PRF_CAMELLIA128_XCBC");
-ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_AES128_CMAC, PRF_CAMELLIA128_XCBC,
+ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_BRNG_HMAC_HBELT, PRF_CAMELLIA128_XCBC,
 	"PRF_HMAC_MD5",
 	"PRF_HMAC_SHA1",
 	"PRF_HMAC_TIGER",
@@ -33,8 +33,12 @@
 	"PRF_HMAC_SHA2_256",
 	"PRF_HMAC_SHA2_384",
 	"PRF_HMAC_SHA2_512",
-	"PRF_AES128_CMAC");
-ENUM_END(pseudo_random_function_names, PRF_AES128_CMAC);
+	"PRF_AES128_CMAC",
+	"PRF_BRNG_CTR_HBELT",
+	"PRF_BRNG_HMAC_HBELT");
+ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_HBELT, PRF_HMAC_HBELT, PRF_BRNG_HMAC_HBELT,
+	"PRF_HMAC_HBELT");
+ENUM_END(pseudo_random_function_names, PRF_HMAC_HBELT);
 
 /*
  * Described in header.
@@ -51,6 +55,10 @@
 			return PRF_HMAC_SHA2_384;
 		case OID_HMAC_SHA512:
 			return PRF_HMAC_SHA2_512;
+		case OID_BRNG_CTR_HBELT:
+			return PRF_BRNG_CTR_HBELT;
+		case OID_BRNG_HMAC_HBELT:
+			return PRF_BRNG_HMAC_HBELT;
 		case OID_HMAC_SHA224:
 		case OID_HMAC_SHA512_224:
 		case OID_HMAC_SHA512_256:
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/prfs/prf.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/prfs/prf.h
--- strongswan-5.8.4/src/libstrongswan/crypto/prfs/prf.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/prfs/prf.h	2022-07-06 15:47:34.838984000 +0300
@@ -52,6 +52,10 @@
 	PRF_HMAC_SHA2_512 = 7,
 	/** RFC4615 */
 	PRF_AES128_CMAC = 8,
+	/** PRFBRNG_CTR */
+	PRF_BRNG_CTR_HBELT = 9,
+	/** PRFBRNG_HMAC */
+	PRF_BRNG_HMAC_HBELT = 10,
 	/** FIPS 186-2-change1 */
 	PRF_FIPS_SHA1_160 = 1025,
 	/** FIPS 186-2-change1, uses fixed output size of 160bit */
@@ -62,6 +66,8 @@
 	PRF_KEYED_SHA1 = 1027,
 	/** draft-kanno-ipsecme-camellia-xcbc, not yet assigned by IANA */
 	PRF_CAMELLIA128_XCBC = 1028,
+	/** STB 34.101.47, 6.1 */
+	PRF_HMAC_HBELT = 65530,
 };
 
 /**
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/proposal/proposal.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/proposal/proposal.c
--- strongswan-5.8.4/src/libstrongswan/crypto/proposal/proposal.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/proposal/proposal.c	2022-07-06 15:47:34.838984000 +0300
@@ -26,6 +26,7 @@
 #include <crypto/prfs/prf.h>
 #include <crypto/crypters/crypter.h>
 #include <crypto/signers/signer.h>
+#include <crypto/key_transformer.h>
 
 ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
 	"PROTO_NONE",
@@ -633,6 +634,8 @@
 	{AUTH_AES_XCBC_96,					PRF_AES128_XCBC					},
 	{AUTH_CAMELLIA_XCBC_96,				PRF_CAMELLIA128_XCBC			},
 	{AUTH_AES_CMAC_96,					PRF_AES128_CMAC					},
+	{AUTH_BELT_HASH_LEGACY,				PRF_BRNG_CTR_HBELT				},
+	{AUTH_BELT_HASH,					PRF_HMAC_HBELT					},
 };
 
 /**
@@ -983,6 +986,7 @@
 	integrity_algorithm_t integrity;
 	pseudo_random_function_t prf;
 	diffie_hellman_group_t group;
+	key_transform_alorithm_t tfmer;
 	const char *plugin_name;
 
 	if (aead)
@@ -1040,19 +1044,20 @@
 	}
 	else
 	{
-		/* Round 1 adds algorithms with at least 128 bit security strength */
+		/* first round, appending BY algos */
 		enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
 		while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
 		{
 			switch (encryption)
 			{
-				case ENCR_AES_CBC:
-				case ENCR_AES_CTR:
-				case ENCR_CAMELLIA_CBC:
-				case ENCR_CAMELLIA_CTR:
-					/* we assume that we support all AES/Camellia sizes */
-					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
-					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+				case ENCR_BELT_CBC:
+				case ENCR_BELT_CFB:
+				case ENCR_BELT_CTR:
+					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, /*256*/ 0);
+					break;
+				case ENCR_BELT_CBC_LEGACY:
+				case ENCR_BELT_CFB_LEGACY:
+				case ENCR_BELT_CTR_LEGACY:
 					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
 					break;
 				default:
@@ -1061,18 +1066,35 @@
 		}
 		enumerator->destroy(enumerator);
 
-		/* Round 2 adds algorithms with less than 128 bit security strength */
+		/* second round, appending others */
 		enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
 		while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
 		{
 			switch (encryption)
 			{
+				case ENCR_AES_CBC:
+				case ENCR_AES_CTR:
+				case ENCR_CAMELLIA_CBC:
+				case ENCR_CAMELLIA_CTR:
+					/* we assume that we support all AES/Camellia sizes */
+					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+					break;
 				case ENCR_3DES:
 					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
 					break;
 				case ENCR_DES:
 					/* no, thanks */
 					break;
+				case ENCR_GOST28147_CFB:
+				case ENCR_GOST28147_CTR:
+					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, /*256*/ 0);
+					break;
+				case ENCR_GOST28147_CFB_LEGACY:
+				case ENCR_GOST28147_CTR_LEGACY:
+					add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+					break;
 				default:
 					break;
 			}
@@ -1084,15 +1106,16 @@
 			return FALSE;
 		}
 
-		/* Round 1 adds algorithms with at least 128 bit security strength */
+		/* first round, appending BY algos */
 		enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
 		while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
 		{
 			switch (integrity)
 			{
-				case AUTH_HMAC_SHA2_256_128:
-				case AUTH_HMAC_SHA2_384_192:
-				case AUTH_HMAC_SHA2_512_256:
+				case AUTH_BELT_HMAC_LEGACY:
+				case AUTH_BELT_MAC_LEGACY:
+				case AUTH_BELT_HMAC:
+				case AUTH_BELT_MAC:
 					add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
 					break;
 				default:
@@ -1101,12 +1124,15 @@
 		}
 		enumerator->destroy(enumerator);
 
-		/* Round 2 adds algorithms with less than 128 bit security strength */
+		/* second round, appending others */
 		enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
 		while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
 		{
 			switch (integrity)
 			{
+				case AUTH_HMAC_SHA2_256_128:
+				case AUTH_HMAC_SHA2_384_192:
+				case AUTH_HMAC_SHA2_512_256:
 				case AUTH_AES_XCBC_96:
 				case AUTH_AES_CMAC_96:
 				case AUTH_HMAC_SHA1_96:
@@ -1114,6 +1140,11 @@
 					break;
 				case AUTH_HMAC_MD5_96:
 					/* no, thanks */
+					break;
+				case AUTH_GOST_MAC_LEGACY:
+				case AUTH_GOST_MAC:
+					add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
+					break;
 				default:
 					break;
 			}
@@ -1132,6 +1163,9 @@
 			case PRF_HMAC_SHA2_512:
 			case PRF_AES128_XCBC:
 			case PRF_AES128_CMAC:
+			case PRF_BRNG_CTR_HBELT:
+			case PRF_BRNG_HMAC_HBELT:
+			case PRF_HMAC_HBELT:
 				add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
 				break;
 			default:
@@ -1170,6 +1204,7 @@
 			case ECP_256_BP:
 			case ECP_384_BP:
 			case ECP_512_BP:
+			case ECP_256_BIGN:
 			case CURVE_25519:
 			case CURVE_448:
 			case NTRU_128_BIT:
@@ -1236,6 +1271,20 @@
 	}
 	enumerator->destroy(enumerator);
 
+	enumerator = lib->crypto->create_key_transformer_enumerator(lib->crypto);
+	while (enumerator->enumerate(enumerator, &tfmer, &plugin_name))
+	{
+		switch (tfmer)
+		{
+			case BELT_KEYREP_TRANSFORM:
+				add_algorithm(this, KEY_TRANSFORM_ALGORITHM, tfmer, 0);
+				break;
+			default:
+				break;
+		}
+	}
+	enumerator->destroy(enumerator);
+
 	return TRUE;
 }
 
@@ -1249,24 +1298,30 @@
 	switch (protocol)
 	{
 		case PROTO_IKE:
+			add_algorithm(this, ENCRYPTION_ALGORITHM,   ENCR_BELT_CFB,        0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,    AUTH_BELT_HMAC,       0);
+			add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_BRNG_HMAC_HBELT,  0);
+			add_algorithm(this, DIFFIE_HELLMAN_GROUP,   ECP_256_BIGN,         0);
+			/*
 			if (!proposal_add_supported_ike(this, FALSE))
 			{
 				destroy(this);
 				return NULL;
-			}
+			}*/
 			break;
 		case PROTO_ESP:
-			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          128);
-			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          192);
-			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          256);
-			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
-			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
-			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
-			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
-			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
-			add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BELT_CFB,           0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_MAC,           0);
 			break;
 		case PROTO_AH:
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_MAC_LEGACY,    0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC_LEGACY,   0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_GOST_MAC_LEGACY,    0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HASH_LEGACY,   0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_MAC,           0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC,          0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_GOST_MAC,           0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HASH,          0);
 			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
 			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
 			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
@@ -1290,6 +1345,7 @@
 	switch (protocol)
 	{
 		case PROTO_IKE:
+			/*
 			this = (private_proposal_t*)proposal_create(protocol, 0);
 			if (!proposal_add_supported_ike(this, TRUE))
 			{
@@ -1297,10 +1353,48 @@
 				return NULL;
 			}
 			return &this->public;
+			*/
+			this = (private_proposal_t*)proposal_create(protocol, 0);
+			if (!proposal_add_supported_ike(this, FALSE))
+			{
+				destroy(this);
+				return NULL;
+			}
+			return &this->public;
 		case PROTO_ESP:
 			/* we currently don't include any AEAD proposal for ESP, as we
 			 * don't know if our kernel backend actually supports it. */
-			return NULL;
+			this = (private_proposal_t*)proposal_create(protocol, 0);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BELT_CFB,                 0);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BELT_CBC,                 0);			
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BELT_CTR,                 0);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BELT_CBC_LEGACY,        256);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BELT_CFB_LEGACY,        256);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BELT_CTR_LEGACY,        256);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_GOST28147_CFB_LEGACY,   256);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_GOST28147_CTR_LEGACY,   256);			
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_GOST28147_CFB,            0);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_GOST28147_CTR,            0);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          128);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          192);
+			add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          256);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_MAC,           0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC,          0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HASH,          0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_MAC_LEGACY,    0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC_LEGACY,   0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_GOST_MAC_LEGACY,    0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_BELT_HASH_LEGACY,   0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_GOST_MAC,           0);			
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
+			add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);			
+			add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+			return &this->public;
+			//return NULL;
+
 		case PROTO_AH:
 		default:
 			return NULL;
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt strongswancont-5.8.4-svc/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt
--- strongswan-5.8.4/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt	2022-07-06 15:47:34.830984000 +0300
@@ -30,6 +30,16 @@
 };
 %%
 null,             ENCRYPTION_ALGORITHM, ENCR_NULL,                 0
+gost28147_ctr_legacy, ENCRYPTION_ALGORITHM, ENCR_GOST28147_CTR_LEGACY, 256
+gost28147_cfb_legacy, ENCRYPTION_ALGORITHM, ENCR_GOST28147_CFB_LEGACY, 256
+belt_cbc_legacy,  ENCRYPTION_ALGORITHM, ENCR_BELT_CBC_LEGACY,      256
+belt_cfb_legacy,  ENCRYPTION_ALGORITHM, ENCR_BELT_CFB_LEGACY,      256
+belt_ctr_legacy,  ENCRYPTION_ALGORITHM, ENCR_BELT_CTR_LEGACY,      256
+gost28147_ctr,    ENCRYPTION_ALGORITHM, ENCR_GOST28147_CTR,        0
+gost28147_cfb,    ENCRYPTION_ALGORITHM, ENCR_GOST28147_CFB,        0
+belt_cbc,         ENCRYPTION_ALGORITHM, ENCR_BELT_CBC,             0
+belt_cfb,         ENCRYPTION_ALGORITHM, ENCR_BELT_CFB,             0
+belt_ctr,         ENCRYPTION_ALGORITHM, ENCR_BELT_CTR,             0
 des,              ENCRYPTION_ALGORITHM, ENCR_DES,                  0
 3des,             ENCRYPTION_ALGORITHM, ENCR_3DES,                 0
 aes,              ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            128
@@ -118,6 +128,14 @@
 twofish128,       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        128
 twofish192,       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        192
 twofish256,       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        256
+belt_hash_legacy, INTEGRITY_ALGORITHM,  AUTH_BELT_HASH_LEGACY,     0
+gost_mac_legacy,  INTEGRITY_ALGORITHM,  AUTH_GOST_MAC_LEGACY,      0
+belt_mac_legacy,  INTEGRITY_ALGORITHM,  AUTH_BELT_MAC_LEGACY,      0
+belt_hmac_legacy, INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC_LEGACY,     0
+belt_hash,        INTEGRITY_ALGORITHM,  AUTH_BELT_HASH,            0
+gost_mac,         INTEGRITY_ALGORITHM,  AUTH_GOST_MAC,             0
+belt_mac,         INTEGRITY_ALGORITHM,  AUTH_BELT_MAC,             0
+belt_hmac,        INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC,            0
 sha,              INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,         0
 sha1,             INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,         0
 sha1_160,         INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_160,        0
@@ -134,6 +152,14 @@
 aesxcbc,          INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,          0
 camelliaxcbc,     INTEGRITY_ALGORITHM,  AUTH_CAMELLIA_XCBC_96,     0
 aescmac,          INTEGRITY_ALGORITHM,  AUTH_AES_CMAC_96,          0
+belt_hash_legacy, INTEGRITY_ALGORITHM,  AUTH_BELT_HASH_LEGACY,     0
+gost_mac_legacy,  INTEGRITY_ALGORITHM,  AUTH_GOST_MAC_LEGACY,      0
+belt_mac_legacy,  INTEGRITY_ALGORITHM,  AUTH_BELT_MAC_LEGACY,      0
+belt_hmac_legacy, INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC_LEGACY,     0
+belt_hash,        INTEGRITY_ALGORITHM,  AUTH_BELT_HASH,            0
+gost_mac,         INTEGRITY_ALGORITHM,  AUTH_GOST_MAC,             0
+belt_mac,         INTEGRITY_ALGORITHM,  AUTH_BELT_MAC,             0
+belt_hmac,        INTEGRITY_ALGORITHM,  AUTH_BELT_HMAC,            0
 prfsha1,          PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1,           0
 prfsha256,        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_256,       0
 prfsha384,        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_384,       0
@@ -142,6 +168,8 @@
 prfaesxcbc,       PSEUDO_RANDOM_FUNCTION, PRF_AES128_XCBC,         0
 prfcamelliaxcbc,  PSEUDO_RANDOM_FUNCTION, PRF_CAMELLIA128_XCBC,    0
 prfaescmac,       PSEUDO_RANDOM_FUNCTION, PRF_AES128_CMAC,         0
+prfbrng_ctr,      PSEUDO_RANDOM_FUNCTION, PRF_BRNG_CTR_HBELT,      0
+prfbrng_hmac,     PSEUDO_RANDOM_FUNCTION, PRF_BRNG_HMAC_HBELT,     0
 modpnone,         DIFFIE_HELLMAN_GROUP, MODP_NONE,                 0
 modpnull,         DIFFIE_HELLMAN_GROUP, MODP_NULL,                 0
 modp768,          DIFFIE_HELLMAN_GROUP, MODP_768_BIT,              0
@@ -173,5 +201,6 @@
 ntru192,          DIFFIE_HELLMAN_GROUP, NTRU_192_BIT,              0
 ntru256,          DIFFIE_HELLMAN_GROUP, NTRU_256_BIT,              0
 newhope128,       DIFFIE_HELLMAN_GROUP, NH_128_BIT,                0
+ecp256bign,       DIFFIE_HELLMAN_GROUP, ECP_256_BIGN,              0
 noesn,            EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS,   0
 esn,              EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS,      0
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/signers/signer.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/signers/signer.c
--- strongswan-5.8.4/src/libstrongswan/crypto/signers/signer.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/signers/signer.c	2022-07-06 15:47:34.806984000 +0300
@@ -24,7 +24,7 @@
 	"HMAC_SHA2_384_384",
 	"HMAC_SHA2_512_512",
 	"CAMELLIA_XCBC_96");
-ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_HMAC_SHA2_512_256, AUTH_CAMELLIA_XCBC_96,
+ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_BELT_HASH_LEGACY, AUTH_CAMELLIA_XCBC_96,
 	"HMAC_MD5_96",
 	"HMAC_SHA1_96",
 	"DES_MAC",
@@ -38,6 +38,15 @@
 	"AES_256_GMAC",
 	"HMAC_SHA2_256_128",
 	"HMAC_SHA2_384_192",
-	"HMAC_SHA2_512_256");
-ENUM_END(integrity_algorithm_names, AUTH_HMAC_SHA2_512_256);
+	"HMAC_SHA2_512_256",
+	"GOST_MAC_LEGACY",
+	"BELT_MAC_LEGACY",
+	"BELT_HMAC_LEGACY",
+	"BELT_HASH_LEGACY");
+ENUM_NEXT(integrity_algorithm_names, AUTH_GOST_MAC, AUTH_BELT_HASH, AUTH_BELT_HASH_LEGACY,
+	"GOST_MAC",
+	"BELT_MAC",
+	"BELT_HMAC",
+	"BELT_HASH");
+ENUM_END(integrity_algorithm_names, AUTH_BELT_HASH);
 
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/signers/signer.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/signers/signer.h
--- strongswan-5.8.4/src/libstrongswan/crypto/signers/signer.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/signers/signer.h	2022-07-06 15:47:34.842984000 +0300
@@ -63,6 +63,12 @@
 	AUTH_HMAC_SHA2_384_192 = 13,
 	/** RFC4868 */
 	AUTH_HMAC_SHA2_512_256 = 14,
+	/** GOST28147 */
+	AUTH_GOST_MAC_LEGACY = 15,
+	/** STB 34.101.31 */
+	AUTH_BELT_MAC_LEGACY = 16,
+	AUTH_BELT_HMAC_LEGACY = 17,
+	AUTH_BELT_HASH_LEGACY = 18,
 	/** private use */
 	AUTH_HMAC_SHA1_128 = 1025,
 	/** SHA256 96 bit truncation variant, supported by Linux kernels */
@@ -75,6 +81,12 @@
 	AUTH_HMAC_SHA2_512_512 = 1029,
 	/** draft-kanno-ipsecme-camellia-xcbc, not yet assigned by IANA */
 	AUTH_CAMELLIA_XCBC_96 = 1030,
+
+	/* private BY space */
+	AUTH_GOST_MAC = 65529,
+	AUTH_BELT_MAC = 65530,
+	AUTH_BELT_HMAC = 65531,
+	AUTH_BELT_HASH = 65532,
 };
 
 /**
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/transform.c strongswancont-5.8.4-svc/src/libstrongswan/crypto/transform.c
--- strongswan-5.8.4/src/libstrongswan/crypto/transform.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/transform.c	2022-07-06 15:47:34.842984000 +0300
@@ -17,14 +17,15 @@
 #include <crypto/hashers/hasher.h>
 #include <crypto/rngs/rng.h>
 
-ENUM_BEGIN(transform_type_names, ENCRYPTION_ALGORITHM, EXTENDED_SEQUENCE_NUMBERS,
+ENUM_BEGIN(transform_type_names, ENCRYPTION_ALGORITHM, KEY_TRANSFORM_ALGORITHM,
 	"ENCRYPTION_ALGORITHM",
 	"PSEUDO_RANDOM_FUNCTION",
 	"INTEGRITY_ALGORITHM",
 	"DIFFIE_HELLMAN_GROUP",
-	"EXTENDED_SEQUENCE_NUMBERS");
+	"EXTENDED_SEQUENCE_NUMBERS",
+	"KEY_TRANSFORM_ALGORITHM");
 ENUM_NEXT(transform_type_names, HASH_ALGORITHM, DETERMINISTIC_RANDOM_BIT_GENERATOR,
-		  EXTENDED_SEQUENCE_NUMBERS,
+		  KEY_TRANSFORM_ALGORITHM,
 	"HASH_ALGORITHM",
 	"RANDOM_NUMBER_GENERATOR",
 	"AEAD_ALGORITHM",
@@ -65,6 +66,8 @@
 			return ext_out_function_names;
 		case DETERMINISTIC_RANDOM_BIT_GENERATOR:
 			return drbg_type_names;
+		case KEY_TRANSFORM_ALGORITHM:
+			return key_transform_algorithm_names;
 		case COMPRESSION_ALGORITHM:
 			break;
 	}
diff -ruN strongswan-5.8.4/src/libstrongswan/crypto/transform.h strongswancont-5.8.4-svc/src/libstrongswan/crypto/transform.h
--- strongswan-5.8.4/src/libstrongswan/crypto/transform.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/crypto/transform.h	2022-07-06 15:47:34.830984000 +0300
@@ -34,6 +34,7 @@
 	INTEGRITY_ALGORITHM = 3,
 	DIFFIE_HELLMAN_GROUP = 4,
 	EXTENDED_SEQUENCE_NUMBERS = 5,
+	KEY_TRANSFORM_ALGORITHM = 6,
 	HASH_ALGORITHM = 256,
 	RANDOM_NUMBER_GENERATOR = 257,
 	AEAD_ALGORITHM = 258,
diff -ruN strongswan-5.8.4/src/libstrongswan/eap/eap.c strongswancont-5.8.4-svc/src/libstrongswan/eap/eap.c
--- strongswan-5.8.4/src/libstrongswan/eap/eap.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/eap/eap.c	2022-07-06 15:47:34.834984000 +0300
@@ -59,7 +59,9 @@
 	"EAP_TNC");
 ENUM_NEXT(eap_type_names, EAP_PT_EAP, EAP_PT_EAP, EAP_TNC,
 	"EAP_PT_EAP");
-ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_PT_EAP,
+ENUM_NEXT(eap_type_names, EAP_BPACE, EAP_DYNAMIC, EAP_PT_EAP,
+	"EAP_BPACE",
+	"EAP_BSTS",
 	"EAP_EXPANDED",
 	"EAP_EXPERIMENTAL",
 	"EAP_RADIUS",
@@ -90,7 +92,9 @@
 	"TNC");
 ENUM_NEXT(eap_type_short_names, EAP_PT_EAP, EAP_PT_EAP, EAP_TNC,
 	"PT");
-ENUM_NEXT(eap_type_short_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_PT_EAP,
+ENUM_NEXT(eap_type_short_names, EAP_BPACE, EAP_DYNAMIC, EAP_PT_EAP,
+	"BPACE",
+	"BSTS",
 	"EXP",
 	"XP",
 	"RAD",
@@ -121,6 +125,8 @@
 		{"pt",			EAP_PT_EAP},
 		{"dynamic",		EAP_DYNAMIC},
 		{"radius",		EAP_RADIUS},
+		{"bpace", 		EAP_BPACE},
+		{"bsts",		EAP_BSTS},
 	};
 
 	for (i = 0; i < countof(types); i++)
diff -ruN strongswan-5.8.4/src/libstrongswan/eap/eap.h strongswancont-5.8.4-svc/src/libstrongswan/eap/eap.h
--- strongswan-5.8.4/src/libstrongswan/eap/eap.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/eap/eap.h	2022-07-06 15:47:34.850984000 +0300
@@ -68,6 +68,8 @@
 	EAP_MSTLV = 33,
 	EAP_TNC = 38,
 	EAP_PT_EAP = 54,
+	EAP_BPACE = 252,
+	EAP_BSTS = 253,
 	EAP_EXPANDED = 254,
 	EAP_EXPERIMENTAL = 255,
 	/** not a method, but an implementation providing different methods */
diff -ruN strongswan-5.8.4/src/libstrongswan/Makefile.am strongswancont-5.8.4-svc/src/libstrongswan/Makefile.am
--- strongswan-5.8.4/src/libstrongswan/Makefile.am	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/Makefile.am	2023-03-28 13:57:36.145408000 +0300
@@ -13,7 +13,7 @@
 crypto/rngs/rng.c crypto/rngs/rng_tester.c \
 crypto/prf_plus.c crypto/signers/signer.c \
 crypto/signers/mac_signer.c crypto/crypto_factory.c crypto/crypto_tester.c \
-crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \
+crypto/diffie_hellman.c crypto/aead.c crypto/key_transformer.c crypto/transform.c \
 crypto/iv/iv_gen.c crypto/iv/iv_gen_rand.c crypto/iv/iv_gen_seq.c \
 crypto/iv/iv_gen_null.c \
 crypto/xofs/xof.c crypto/xofs/xof_bitspender.c \
@@ -32,9 +32,10 @@
 database/database_factory.c fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \
 ipsec/ipsec_types.c \
 networking/host.c networking/host_resolver.c networking/packet.c \
-networking/tun_device.c networking/streams/stream_manager.c \
+networking/streams/stream_manager.c \
 networking/streams/stream.c networking/streams/stream_service.c \
 networking/streams/stream_tcp.c networking/streams/stream_service_tcp.c \
+networking/streams/stream_unix.c networking/streams/stream_service_unix.c \
 pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \
 processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \
 processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \
@@ -55,8 +56,21 @@
     threading/rwlock.c \
     threading/spinlock.c \
     threading/semaphore.c \
-    networking/streams/stream_unix.c \
-    networking/streams/stream_service_unix.c
+    networking/tun_device.c
+else
+  libstrongswan_la_SOURCES += \
+    threading/windows/thread.c \
+    threading/windows/thread_value.c \
+    threading/windows/mutex.c \
+    threading/windows/rwlock.c \
+    threading/windows/spinlock.c \
+    threading/windows/semaphore.c \
+    utils/compat/windows.c \
+    utils/windows_helper.c \
+    networking/windows_tun.c
+if USE_WINTUN
+  libstrongswan_la_SOURCES += networking/wintun_support.c
+endif
 endif
 
 # private header files
@@ -77,8 +91,8 @@
 crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/nonce_gen.h \
 crypto/prf_plus.h crypto/signers/signer.h crypto/signers/mac_signer.h \
 crypto/crypto_factory.h crypto/crypto_tester.h crypto/diffie_hellman.h \
-crypto/aead.h crypto/transform.h crypto/pkcs5.h crypto/iv/iv_gen.h \
-crypto/iv/iv_gen_rand.h crypto/iv/iv_gen_seq.h crypto/iv/iv_gen_null.h \
+crypto/aead.h crypto/key_transformer.h crypto/transform.h crypto/pkcs5.h \
+crypto/iv/iv_gen.h crypto/iv/iv_gen_rand.h crypto/iv/iv_gen_seq.h crypto/iv/iv_gen_null.h \
 crypto/xofs/xof.h crypto/xofs/xof_bitspender.h crypto/xofs/mgf1.h \
 credentials/credential_factory.h credentials/builder.h \
 credentials/cred_encoding.h credentials/keys/private_key.h \
@@ -99,7 +113,7 @@
 database/database.h database/database_factory.h fetcher/fetcher.h \
 fetcher/fetcher_manager.h eap/eap.h pen/pen.h ipsec/ipsec_types.h \
 networking/host.h networking/host_resolver.h networking/packet.h \
-networking/tun_device.h networking/streams/stream.h \
+networking/streams/stream.h \
 networking/streams/stream_unix.h networking/streams/stream_service_unix.h \
 networking/streams/stream_service_systemd.h \
 networking/streams/stream_tcp.h networking/streams/stream_service_tcp.h \
@@ -122,6 +136,18 @@
 utils/utils/atomics.h utils/utils/types.h utils/utils/byteorder.h \
 utils/utils/string.h utils/utils/memory.h utils/utils/tty.h utils/utils/path.h \
 utils/utils/status.h utils/utils/object.h utils/utils/time.h utils/utils/align.h
+if USE_WINDOWS
+  nobase_strongswan_include_HEADERS += \
+    utils/windows_helper.h \
+    networking/windows_tun.h
+if USE_WINTUN
+ nobase_strongswan_include_HEADERS += \
+   networking/wintun_support.h
+endif
+else
+ nobase_strongswan_include_HEADERS += \
+    networking/tun_device.h
+endif
 endif
 
 library.lo :	$(top_builddir)/config.status
@@ -146,19 +172,14 @@
 AM_YFLAGS = -v -d
 
 if USE_WINDOWS
-  libstrongswan_la_LIBADD += -lws2_32 -lpsapi
-  libstrongswan_la_SOURCES += \
-    threading/windows/thread.c \
-    threading/windows/thread_value.c \
-    threading/windows/mutex.c \
-    threading/windows/rwlock.c \
-    threading/windows/spinlock.c \
-    threading/windows/semaphore.c \
-    utils/compat/windows.c
+  libstrongswan_la_LIBADD += -lws2_32 -lpsapi -lcfgmgr32 -lsetupapi
 else
   libstrongswan_la_LIBADD += $(PTHREADLIB)
 endif
 
+if USE_WINTUN
+    libstrongswan_la_LIBADD += -lwinpthread
+endif
 if USE_DBGHELP
   libstrongswan_la_LIBADD += -ldbghelp
   AM_CPPFLAGS += -DHAVE_DBGHELP
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/streams/stream_manager.c strongswancont-5.8.4-svc/src/libstrongswan/networking/streams/stream_manager.c
--- strongswan-5.8.4/src/libstrongswan/networking/streams/stream_manager.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/streams/stream_manager.c	2022-07-08 11:28:38.154772000 +0300
@@ -17,10 +17,9 @@
 
 #include "stream_tcp.h"
 #include "stream_service_tcp.h"
-#ifndef WIN32
-# include "stream_unix.h"
-# include "stream_service_unix.h"
-#endif
+#include "stream_unix.h"
+#include "stream_service_unix.h"
+
 #ifdef USE_SYSTEMD
 # include "stream_service_systemd.h"
 #endif
@@ -205,10 +204,8 @@
 {
 	remove_stream(this, stream_create_tcp);
 	remove_service(this, stream_service_create_tcp);
-#ifndef WIN32
 	remove_stream(this, stream_create_unix);
 	remove_service(this, stream_service_create_unix);
-#endif
 #ifdef USE_SYSTEMD
 	remove_service(this, stream_service_create_systemd);
 #endif
@@ -243,10 +240,8 @@
 
 	add_stream(this, "tcp://", stream_create_tcp);
 	add_service(this, "tcp://", stream_service_create_tcp);
-#ifndef WIN32
 	add_stream(this, "unix://", stream_create_unix);
 	add_service(this, "unix://", stream_service_create_unix);
-#endif
 #ifdef USE_SYSTEMD
 	add_service(this, "systemd://", stream_service_create_systemd);
 #endif
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/streams/stream_service_unix.c strongswancont-5.8.4-svc/src/libstrongswan/networking/streams/stream_service_unix.c
--- strongswan-5.8.4/src/libstrongswan/networking/streams/stream_service_unix.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/streams/stream_service_unix.c	2022-07-08 11:41:12.759409000 +0300
@@ -18,9 +18,103 @@
 
 #include <errno.h>
 #include <unistd.h>
+#ifndef WIN32
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/stat.h>
+#else
+#include <windows.h>
+#include <accctrl.h>
+#include <aclapi.h>
+#endif
+
+bool change_owner(int fd, struct sockaddr_un *addr)
+{
+#ifdef WIN32
+    /* Change owner of socket */
+    /* https://docs.microsoft.com/en-us/windows/win32/secauthz/taking-object-ownership-in-c-- */
+	SECURITY_DESCRIPTOR *security_descriptor = malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
+	SECURITY_ATTRIBUTES security_attributes = {
+		.nLength = sizeof(SECURITY_ATTRIBUTES),
+		.bInheritHandle = FALSE,
+	};;
+	PACL pACL = NULL;
+	EXPLICIT_ACCESS ea[2];
+	SID *pAdminSID = NULL;
+	SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
+
+	char buf[512];
+	int ret;
+        /* BUILTIN\Administrator  */
+	if(!AllocateAndInitializeSid(&SIDAuthNT, 2,
+                     SECURITY_BUILTIN_DOMAIN_RID,
+                     DOMAIN_ALIAS_RID_ADMINS,
+                     0, 0, 0, 0, 0, 0,
+                     (void **) &pAdminSID)) 
+	{
+		DBG1(DBG_LIB, "Failed to initialize SID: %s", dlerror_mt(buf, sizeof(buf)));
+		goto cleanup;
+	}
+
+	memset(ea, 0, sizeof(EXPLICIT_ACCESS));
+	ea[0].grfAccessPermissions = KEY_ALL_ACCESS;
+	ea[0].grfAccessMode = SET_ACCESS;
+	ea[0].grfInheritance= NO_INHERITANCE;
+	ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+	ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
+	ea[0].Trustee.ptstrName  = (LPTSTR) pAdminSID;
+	if (!InitializeSecurityDescriptor(security_descriptor, SECURITY_DESCRIPTOR_REVISION))
+	{
+		DBG1(DBG_LIB, "Failed to initialize security descriptor: %s", dlerror_mt(buf, sizeof(buf)));
+		goto cleanup;
+	}
+	if ((ret=SetEntriesInAcl(1, ea, NULL, &pACL)) != ERROR_SUCCESS)
+	{
+		DBG1(DBG_LIB, "Failed to set ACL entries: %s", human_readable_error(buf, ret, sizeof(buf)));
+		goto cleanup;		
+	}
+	if ((ret=SetSecurityDescriptorDacl(security_descriptor, TRUE, pACL, FALSE)))
+	{
+		DBG1(DBG_LIB, "Failed to set security descriptor in ACL: %s", dlerror_mt(buf, sizeof(buf)));
+		goto cleanup;
+	}
+	security_attributes.lpSecurityDescriptor = security_descriptor; 
+
+        if(SetNamedSecurityInfo(
+        addr->sun_path,
+        SE_FILE_OBJECT,
+        DACL_SECURITY_INFORMATION,
+        NULL, NULL,                  
+        pACL,                        
+        NULL))
+        {
+            ret = TRUE;
+        }
+        
+cleanup:
+        FreeSid(pAdminSID);
+        return ret;
+#else
+	if (lib->caps->check(lib->caps, CAP_CHOWN))
+	{
+		if (chown(addr->sun_path, lib->caps->get_uid(lib->caps),
+				  lib->caps->get_gid(lib->caps)) != 0)
+		{
+			DBG1(DBG_NET, "changing socket owner/group for '%s' failed: %s",
+				 uri, strerror(errno));
+		}
+	}
+	else
+	{
+		if (chown(addr->sun_path, -1, lib->caps->get_gid(lib->caps)) != 0)
+		{
+			DBG1(DBG_NET, "changing socket group for '%s' failed: %s",
+				 uri, strerror(errno));
+		}
+	}
+        return TRUE;
+#endif
+}
 
 /**
  * See header
@@ -64,22 +158,9 @@
 	 * dropping caps. This requires the user that charon starts as to:
 	 * a) Have write access to the socket dir.
 	 * b) Belong to the group that charon will run under after dropping caps. */
-	if (lib->caps->check(lib->caps, CAP_CHOWN))
-	{
-		if (chown(addr.sun_path, lib->caps->get_uid(lib->caps),
-				  lib->caps->get_gid(lib->caps)) != 0)
-		{
-			DBG1(DBG_NET, "changing socket owner/group for '%s' failed: %s",
-				 uri, strerror(errno));
-		}
-	}
-	else
+	if (!change_owner(fd, &addr))
 	{
-		if (chown(addr.sun_path, -1, lib->caps->get_gid(lib->caps)) != 0)
-		{
-			DBG1(DBG_NET, "changing socket group for '%s' failed: %s",
-				 uri, strerror(errno));
-		}
+		DBG1(DBG_NET, "Failed to change owner of socket '%s': %s", uri, strerror(errno));
 	}
 	if (listen(fd, backlog) < 0)
 	{
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/streams/stream_unix.h strongswancont-5.8.4-svc/src/libstrongswan/networking/streams/stream_unix.h
--- strongswan-5.8.4/src/libstrongswan/networking/streams/stream_unix.h	2016-04-22 23:01:35.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/streams/stream_unix.h	2022-07-08 11:41:11.295378000 +0300
@@ -21,7 +21,9 @@
 #ifndef STREAM_UNIX_H_
 #define STREAM_UNIX_H_
 
+#ifndef WIN32
 #include <sys/un.h>
+#endif
 
 /**
  * Create a stream for UNIX sockets.
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/tun_device.c strongswancont-5.8.4-svc/src/libstrongswan/networking/tun_device.c
--- strongswan-5.8.4/src/libstrongswan/networking/tun_device.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/tun_device.c	2020-11-30 16:52:55.000000000 +0300
@@ -26,7 +26,9 @@
 #if !TARGET_OS_OSX
 #define TUN_DEVICE_NOT_SUPPORTED
 #endif
-#elif !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H)
+#endif
+
+#if ! (defined(__linux__) || defined(HAVE_NET_IF_TUN_H) || defined(USE_WINTUN))
 #define TUN_DEVICE_NOT_SUPPORTED
 #endif
 
@@ -42,15 +44,14 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <netinet/in.h>
 #include <string.h>
-#include <sys/ioctl.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
 #include <net/if.h>
-
 #ifdef __APPLE__
 #include <net/if_utun.h>
 #include <netinet/in_var.h>
@@ -65,7 +66,6 @@
 #else
 #include <net/if_tun.h>
 #endif
-
 #define TUN_DEFAULT_MTU 1500
 
 typedef struct private_tun_device_t private_tun_device_t;
@@ -83,14 +83,13 @@
 	int tunfd;
 
 	/**
-	 * Name of the TUN device
-	 */
-	char if_name[IFNAMSIZ];
-
-	/**
 	 * Socket used for ioctl() to set interface addr, ...
 	 */
 	int sock;
+	/**
+	 * Name of the TUN device
+	 */
+	char if_name[IFNAMSIZ];
 
 	/**
 	 * The current MTU
@@ -222,31 +221,8 @@
 		return FALSE;
 	}
 	return TRUE;
-}
 
 #endif /* __FreeBSD__ */
-
-METHOD(tun_device_t, set_address, bool,
-	private_tun_device_t *this, host_t *addr, uint8_t netmask)
-{
-	if (!set_address_impl(this, addr, netmask))
-	{
-		return FALSE;
-	}
-	DESTROY_IF(this->address);
-	this->address = addr->clone(addr);
-	this->netmask = netmask;
-	return TRUE;
-}
-
-METHOD(tun_device_t, get_address, host_t*,
-	private_tun_device_t *this, uint8_t *netmask)
-{
-	if (netmask && this->address)
-	{
-		*netmask = this->netmask;
-	}
-	return this->address;
 }
 
 METHOD(tun_device_t, up, bool,
@@ -315,12 +291,35 @@
 	return this->mtu;
 }
 
+
+METHOD(tun_device_t, set_address, bool,
+	private_tun_device_t *this, host_t *addr, uint8_t netmask)
+{
+	if (!set_address_impl(this, addr, netmask))
+	{
+		return FALSE;
+	}
+	DESTROY_IF(this->address);
+	this->address = addr->clone(addr);
+	this->netmask = netmask;
+	return TRUE;
+}
+
+METHOD(tun_device_t, get_address, host_t*,
+	private_tun_device_t *this, uint8_t *netmask)
+{
+	if (netmask && this->address)
+	{
+		*netmask = this->netmask;
+	}
+	return this->address;
+}
+
 METHOD(tun_device_t, get_name, char*,
 	private_tun_device_t *this)
 {
 	return this->if_name;
 }
-
 METHOD(tun_device_t, get_fd, int,
 	private_tun_device_t *this)
 {
@@ -330,8 +329,7 @@
 METHOD(tun_device_t, write_packet, bool,
 	private_tun_device_t *this, chunk_t packet)
 {
-	ssize_t s;
-
+        ssize_t s;
 #ifdef __APPLE__
 	/* UTUN's expect the packets to be prepended by a 32-bit protocol number
 	 * instead of parsing the packet again, we assume IPv4 for now */
@@ -408,12 +406,9 @@
 	free(this);
 }
 
-/**
- * Initialize the tun device
- */
-static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
+bool init_tun(private_tun_device_t *this, const char *name_tmpl)
 {
-#ifdef __APPLE__
+#if defined(__APPLE__)
 
 	struct ctl_info info;
 	struct sockaddr_ctl addr;
@@ -533,8 +528,7 @@
 		DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno));
 	}
 	return this->tunfd > 0;
-
-#endif /* !__APPLE__ */
+#endif
 }
 
 /*
@@ -543,7 +537,7 @@
 tun_device_t *tun_device_create(const char *name_tmpl)
 {
 	private_tun_device_t *this;
-
+	
 	INIT(this,
 		.public = {
 			.read_packet = _read_packet,
@@ -567,7 +561,6 @@
 		return NULL;
 	}
 	DBG1(DBG_LIB, "created TUN device: %s", this->if_name);
-
 	this->sock = socket(AF_INET, SOCK_DGRAM, 0);
 	if (this->sock < 0)
 	{
@@ -577,5 +570,4 @@
 	}
 	return &this->public;
 }
-
 #endif /* TUN devices supported */
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/tun_device.h strongswancont-5.8.4-svc/src/libstrongswan/networking/tun_device.h
--- strongswan-5.8.4/src/libstrongswan/networking/tun_device.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/tun_device.h	2020-11-30 16:52:55.000000000 +0300
@@ -25,6 +25,9 @@
 
 #include <networking/host.h>
 
+#ifdef WIN32
+#include "windows_tun.h"
+#else
 typedef struct tun_device_t tun_device_t;
 
 /**
@@ -121,4 +124,5 @@
  */
 tun_device_t *tun_device_create(const char *name_tmpl);
 
+#endif /* !WIN32 */
 #endif /** TUN_DEVICE_H_ @}*/
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/windows_tun.c strongswancont-5.8.4-svc/src/libstrongswan/networking/windows_tun.c
--- strongswan-5.8.4/src/libstrongswan/networking/windows_tun.c	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/windows_tun.c	2022-12-08 15:27:25.366556000 +0300
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2020 Noel Kuntze <noel.kuntze@thermi.consulting>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#include <winsock2.h>
+#include <windows.h>
+#include <cfgmgr32.h>
+#include <setupapi.h>
+#include <devpkey.h>
+#include <winreg.h>
+#include <utils/windows_helper.h>
+#include <ddk/ndisguid.h>
+
+#include <string.h>
+
+#include "../utils/utils/memory.h"
+#include "../collections/linked_list.h"
+
+#include "windows_tun.h"
+#include "wintun_support.h"
+
+/* Stub. */
+struct private_openvpn_tun_device_t {
+} typedef private_openvpn_tun_device_t;
+
+ /*
+ * Helper function to get the next HardwareID in the
+ * SP_DRVINFO_DETAIL_DATA_A.HardwareID linear array.
+ * (Looks like this: "abcdef\0ghijkl\0mnopqrs\0\0". Empty string (Just a NULL byte)
+ * denotes the end of the array)
+ *
+ * @param pile			linear character array of the hardwareIDs as they are part of
+ *						the SP_DRVINFO_DETAIL_DATA_A struct.
+ * @param offset		pointer to a location in which the end position of the search algorithm is stored.
+ *						It is used to keep the offset between multiple calls of the function and ease its use.
+ *						The value is the position at which the resulting string ends (strlen() + 1, or its NULL byte)
+ * @return				The next hardwareID or NULL, if the end of the array was reached.
+ */
+char *windows_drv_info_get_next_hardwareid(char *pile, size_t *offset)
+{
+	size_t len = 0, old_offset = 0;
+	old_offset = *offset;
+	len = strlen(pile + *offset);
+	*offset += len + 1;
+	if (len == 0)
+	{
+		/* End of the list, empty string. */
+		return NULL;
+	}
+	return pile + old_offset;
+}
+
+/*
+ * Wide string version of windows_drv_info_get_next_hardwareid 
+ */
+/*
+wchar_t *windows_drv_info_get_next_hardwareid_wide(wchar_t *pile, size_t *offset)
+{
+	size_t len = 0, old_offset = 0;
+	while(true)
+	{
+		old_offset = *offset;
+		len = wcslen(pile + *offset);
+		*offset += len + sizeof(wchar_t);
+		if (len == 0)
+		{
+			End of the list, empty string. 
+			return NULL;
+		}
+		return pile + old_offset;
+	}
+}
+*/
+
+/*
+ * Helper function that wraps around windows_drv_info_get_next_hardwareid.
+ * It returns true if needle is in the pile (pile is a linear, empty string terminated array of strings).
+ * It returns false if needle is NOT in the pile.
+ *
+ * @param pile			A linear array of strings. Terminated by an empty string.
+ * @param needle		A string to find in pile.
+ *
+ * @returns				Returns whether needle is in pile
+ */
+bool find_matching_hardwareid(char *pile, char* needle)
+{
+	size_t offset = 0;
+	char *item;
+	while(true)
+	{
+		item = windows_drv_info_get_next_hardwareid(pile, &offset);
+		if (!item)
+		{
+			return false;
+		}
+
+		if(!strcmp(item, needle))
+		{
+			return true;
+		}
+	}
+	return false;
+}
+/*
+ * Wide version of find_matching_hardwareid
+ */
+/*
+bool find_matching_hardwareid_wide(wchar_t *pile, wchar_t* needle)
+{
+	size_t offset = 0;
+	wchar_t *item;
+	while(true)
+	{
+		item = windows_drv_info_get_next_hardwareid_wide(pile, &offset);
+		DBG0(DBG_LIB, "next hardwareID: %ls", item);
+		if (!item)
+		{
+			return false;
+		}
+
+		if(wcscmp(item, needle) == 0)
+		{
+			return true;
+		}
+	}
+}
+*/
+
+char *windows_setupapi_get_friendly_name(char *buffer, size_t buf_len, HDEVINFO dev_info_set,
+										 SP_DEVINFO_DATA *dev_info_data)
+{
+	memwipe(buffer, buf_len);
+	size_t required_length;
+	DWORD prop_type;
+	char buf[512];
+
+	if (!SetupDiGetDeviceRegistryPropertyA(
+		dev_info_set, dev_info_data,
+		SPDRP_DEVICEDESC,
+		&prop_type,
+		buffer,
+		buf_len,
+		(DWORD *)&required_length))
+	{
+		if (!SetupDiGetDeviceRegistryPropertyA(
+			dev_info_set, dev_info_data,
+			SPDRP_FRIENDLYNAME,
+			&prop_type,
+			buffer,
+			buf_len,
+			(DWORD *)&required_length))
+		{
+			// Try hardware path instead 
+			if (SetupDiGetDeviceRegistryPropertyA(
+				dev_info_set, dev_info_data,
+				SPDRP_LOCATION_INFORMATION,
+				&prop_type,
+				buffer,
+				buf_len,
+				(DWORD *)&required_length))
+			{
+				if (strcmp(buffer, "\r\n") || strcmp(buffer, ""))
+				{
+					ignore_result(snprintf(buffer, buf_len, "<unknown>"));
+				}
+				return buffer;
+			}
+			else
+			{
+				DBG2(DBG_LIB, "Failed to retrieve the hardware location of a device: %s", dlerror_mt(buf, sizeof(buf)));
+			}
+		}
+	}
+	return buffer;
+}
+
+/*
+bool windows_get_driver_info_data_a(
+	HDEVINFO *dev_info_set,
+	SP_DEVINFO_DATA *dev_info_data,
+	SP_DRVINFO_DATA_A *drv_info_data,
+	PSP_DRVINFO_DETAIL_DATA_A *drv_info_detail_data,
+	DWORD *property_buffer_length,
+	DWORD *required_length
+)
+{
+	DWORD error, ret;
+	char buf[512];
+	while(TRUE)
+	{
+	if (!(ret=SetupDiGetDriverInfoDetailA(
+		*dev_info_set,
+		dev_info_data,
+		drv_info_data,
+		*drv_info_detail_data,
+		*property_buffer_length,
+		required_length
+	)))
+	{
+		error = GetLastError();
+		switch (error) {
+			case 0:
+				break;
+			case ERROR_INVALID_USER_BUFFER:
+				DBG1(DBG_LIB, "Error %d: Insufficient memory.", error);
+				// allocate memory
+				*drv_info_detail_data = realloc(
+					*drv_info_detail_data,
+					*required_length + sizeof(SP_DRVINFO_DETAIL_DATA_A));
+				(*drv_info_detail_data)->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
+				*property_buffer_length = *required_length + sizeof(SP_DRVINFO_DETAIL_DATA_A);
+				DBG0(DBG_LIB, "required_length: %u", *required_length);
+				if (!SetupDiGetDriverInfoDetailA(
+					*dev_info_set,
+					dev_info_data,
+					drv_info_data,
+					*drv_info_detail_data,
+					*property_buffer_length,
+					required_length
+				))
+				{
+					error = GetLastError();
+					DBG1(DBG_LIB,
+						"Previous required length was bogus. New error is %d: %s",
+						error, dlerror_mt(buf, sizeof(buf)));
+				}
+				break;
+			case ERROR_INSUFFICIENT_BUFFER:
+				DBG1(DBG_LIB, "Invalid user buffer (for some reason) %d", error);
+				return FALSE;
+				break;
+			default:
+				DBG1(DBG_LIB, "A different error occured %d: %s",
+				 error, dlerror_mt(buf, sizeof(buf)));
+				return FALSE;
+				break;
+		}
+	} else {
+		DBG1(DBG_LIB, "Received error: %s", dlerror_mt(buf, sizeof(buf)));
+	}
+	}
+	return FALSE;
+} */
+
+bool check_hardwareids(SP_DRVINFO_DETAIL_DATA_A *drv_info_detail_data)
+{
+	/* Make sure CompatIDsOffset indicates more than one HardwareID is in it
+	 * but also there actually is a hardware ID in the HardwareID field,
+	 * instead of just a \r(\n) (Windows DOES do that!) */
+	if (drv_info_detail_data->CompatIDsOffset > 1 &&
+		drv_info_detail_data->HardwareID &&
+		drv_info_detail_data->HardwareID[0] != '\r')
+	{
+		DBG2(DBG_LIB, "HardwareID: %%s",
+			drv_info_detail_data->HardwareID);
+		if (!strcmp(
+			drv_info_detail_data->HardwareID,
+			WINTUN_COMPONENT_ID)) {
+			/* HardwareID matches */
+			DBG2(DBG_LIB, "HardwareID %s matches %s",
+				drv_info_detail_data->HardwareID,
+				WINTUN_COMPONENT_ID);
+			return TRUE;
+		} else {
+			DBG2(DBG_LIB, "HardwareID does not match");
+			return FALSE;
+		}
+	}
+	// Iterate over HardwareID array in drv_info_detail_data
+	if(!(WINDOWS_IS_UNITIALIZED(drv_info_detail_data->CompatIDsOffset)) &&
+		drv_info_detail_data->CompatIDsLength > 0)
+	{	
+		DBG2(DBG_LIB, "HardwareID: %hs", drv_info_detail_data->HardwareID);
+		/* compatIDs are in wide characters. Need to convert all fields into compatible */
+		if(find_matching_hardwareid(
+			drv_info_detail_data->HardwareID,
+			(char *) WINTUN_COMPONENT_ID))
+		{
+			return TRUE;			
+		} else {
+			DBG2(DBG_LIB, "ID %s is not in compatible hardware IDs", WINTUN_COMPONENT_ID);
+			return FALSE;
+		}
+	}
+	return FALSE;
+}
+
+/* Described in header */
+linked_list_t *string_array_to_linked_list(char *pile)
+{
+	linked_list_t *list = linked_list_create();
+	size_t offset = 0;
+	char *item;
+	while(true)
+	{
+		item = windows_drv_info_get_next_hardwareid(pile, &offset);
+		if (!item)
+		{
+			return list;
+		}
+		list->insert_last(list, item);
+	}
+	return list;
+}
+
+/* Stub */
+tun_device_t *try_configure_openvpn(const char *name_tmpl)
+{
+	return NULL;
+}
+/*
+ * Described in header
+ */
+
+tun_device_t *tun_device_create(const char *name_tmpl)
+{
+		tun_device_t *public = NULL;
+#ifdef USE_WINTUN
+	public = try_configure_wintun(name_tmpl);
+	/* if (!public)
+	{
+		public = try_configure_openvpn(name_tmpl);
+	} */
+	if(!public)
+	{
+		DBG0(DBG_LIB, "failed to create TUN device.");
+		return NULL;
+	}
+	DBG0(DBG_LIB, "created TUN device: %s", public->get_name(public));
+#else
+	DBG1(DBG_LIB, "TUN devices are not supported");
+#endif
+	return public;
+}
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/windows_tun.h strongswancont-5.8.4-svc/src/libstrongswan/networking/windows_tun.h
--- strongswan-5.8.4/src/libstrongswan/networking/windows_tun.h	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/windows_tun.h	2020-11-30 16:52:55.000000000 +0300
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2020 Noel Kuntze <noel.kuntze@thermi.consulting>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+/* 
+ * File:   windows_tun.h
+ * Author: thermi
+ *
+ * Created on 27. April 2020, 14:58
+ */
+
+#ifndef WINDOWS_TUN_H
+#define WINDOWS_TUN_H
+
+typedef struct tun_device_t tun_device_t;
+
+#ifdef USE_WINTUN
+#include "wintun_support.h"
+#endif
+
+/**
+ * Class to create TUN devices
+ *
+ * Creating such a device requires the CAP_NET_ADMIN capability.
+ */
+struct tun_device_t {
+
+	/**
+	 * Read a packet from the TUN device
+	 *
+	 * @note This call blocks until a packet is available. It is a thread
+	 * cancellation point.
+	 *
+	 * @param packet		the packet read from the device, allocated
+	 * @return				TRUE if successful
+	 */
+	bool (*read_packet)(tun_device_t *this, chunk_t *packet);
+
+	/**
+	 * Write a packet to the TUN device
+	 *
+	 * @param packet		the packet to write to the TUN device
+	 * @return				TRUE if successful
+	 */
+	bool (*write_packet)(tun_device_t *this, chunk_t packet);
+
+	/**
+	 * Set the IP address of the device
+	 *
+	 * @param addr			the desired interface address
+	 * @param netmask		the netmask to use
+	 * @return				TRUE if operation successful
+	 */
+	bool (*set_address)(tun_device_t *this, host_t *addr, uint8_t netmask);
+
+	/**
+	 * Get the IP address previously assigned to using set_address().
+	 *
+	 * @param netmask		pointer receiving the configured netmask, or NULL
+	 * @return				address previously set, NULL if none
+	 */
+	host_t* (*get_address)(tun_device_t *this, uint8_t *netmask);
+
+	/**
+	 * Bring the TUN device up
+	 *
+	 * @return				TRUE if operation successful
+	 */
+	bool (*up)(tun_device_t *this);
+
+	/**
+	 * Set the MTU for this TUN device
+	 *
+	 * @param mtu			new MTU
+	 * @return				TRUE if operation successful
+	 */
+	bool (*set_mtu)(tun_device_t *this, int mtu);
+
+	/**
+	 * Get the current MTU for this TUN device
+	 *
+	 * @return				current MTU
+	 */
+	int (*get_mtu)(tun_device_t *this);
+
+	/**
+	 * Get the interface name of this device
+	 *
+	 * @return				interface name
+	 */
+	char *(*get_name)(tun_device_t *this);
+
+	/**
+	 * Get the underlying HANDLE.
+	 *
+	 * @return                              file HANDLE of this tun device
+	 */
+	HANDLE (*get_handle)(tun_device_t *this);
+
+	/**
+	 * Destroy a tun_device_t
+	 */
+	void (*destroy)(tun_device_t *this);
+
+};
+
+ /*
+ * Helper function to get the next HardwareID in the
+ * SP_DRVINFO_DETAIL_DATA_A.HardwareID linear array.
+ * (Looks like this: "abcdef\0ghijkl\0mnopqrs\0\0". Empty string (Just a NULL byte)
+ * denotes the end of the array)
+ *
+ * @param pile			linear character array of the hardwareIDs as they are part of
+ *						the SP_DRVINFO_DETAIL_DATA_A struct.
+ * @param offset		pointer to a location in which the end position of the search algorithm is stored.
+ *						It is used to keep the offset between multiple calls of the function and ease its use.
+ *						The value is the position at which the resulting string ends (strlen() + 1, or its NULL byte)
+ * @return				The next hardwareID or NULL, if the end of the array was reached.
+ */
+char *windows_drv_info_get_next_hardwareid(char *pile, size_t *offset);
+
+/*
+ * Helper function that wraps around windows_drv_info_get_next_hardwareid.
+ * It returns true if needle is in the pile (pile is a linear, empty string terminated array of strings).
+ * It returns false if needle is NOT in the pile.
+ *
+ * @param pile			A linear array of strings. Terminated by an empty string.
+ * @param needle		A string to find in pile.
+ *
+ * @return				Returns whether needle is in pile
+ */
+bool find_matching_hardwareid(char *pile, char* needle);
+
+/*
+ * Helper function for getting a nice human readable name for a specific device.
+ * @param buffer                Allocated buffer that receives the device name.
+ * @param buf_len               Length of the buffer in bytes.
+ * @param dev_info_set          device info set that contains the device
+ * @param dev_info_data         Data
+ * @return                      zero byte terminated friendly name. Same as buffer.
+ */
+char *windows_setupapi_get_friendly_name(char *buffer, size_t buf_len, HDEVINFO dev_info_set, SP_DEVINFO_DATA *dev_info_data);
+
+/*
+bool windows_get_driver_info_data_a(
+	HDEVINFO *dev_info_set,
+	SP_DEVINFO_DATA *dev_info_data,
+	SP_DRVINFO_DATA_A *drv_info_data,
+	PSP_DRVINFO_DETAIL_DATA_A *drv_info_detail_data,
+	DWORD *property_buffer_length,
+	DWORD *required_length
+);
+*/
+
+bool check_hardwareids(SP_DRVINFO_DETAIL_DATA_A *drv_info_detail_data);
+
+
+/*
+ * Helper function for transforming double zero byte terminated string array to linked_list_t
+ * @param pile                  double zero byte terminated string array
+ * @return                      linked_list_t with copied strings of the string array, heap allocated
+ */
+linked_list_t *string_array_to_linked_list(char *pile);
+
+/*
+ * Implementation of tun_device_create for Windows.
+ * @param name_tmpl     zero byte terminated string that contains the name template for the interface.
+ */
+tun_device_t *tun_device_create(const char *name_tmpl);
+
+
+#endif /* WINDOWS_TUN_H */
+
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/wintun_support.c strongswancont-5.8.4-svc/src/libstrongswan/networking/wintun_support.c
--- strongswan-5.8.4/src/libstrongswan/networking/wintun_support.c	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/wintun_support.c	2023-04-30 13:04:52.664123000 +0300
@@ -0,0 +1,1256 @@
+/*
+ * Copyright (C) 2020 Noel Kuntze <noel.kuntze@thermi.consulting>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+
+#include <winsock2.h>
+#include <ifdef.h>
+/* For NTSTATUS, potentially defined in bcrypt.h if it exists */
+#include <winternl.h>
+#include <netioapi.h>
+#include <windows.h>
+#include <cfgmgr32.h>
+#include <setupapi.h>
+#include <devpkey.h>
+#include <winreg.h>
+#include <utils/windows_helper.h>
+
+#include "wintun_support.h"
+#include <threading/mutex.h>
+
+typedef struct private_windows_wintun_device_t private_windows_wintun_device_t;
+
+struct private_windows_wintun_device_t {
+
+	/**
+	 * Public interface
+	 */
+	tun_device_t public;
+
+	/**
+	 * The TUN device's HANDLE
+	 */
+	HANDLE tun_handle;
+
+	/**
+	 * The TUN device's rings
+	 */
+	TUN_REGISTER_RINGS *rings;
+
+	/**
+	 * Name of the TUN device
+	 */
+	char if_name[IFNAMSIZ];
+	
+	/**
+	 * Index of the interface
+	 */
+	uint32_t ifindex;
+
+	/**
+	 * The current MTU
+	 */
+	int mtu;
+
+	/**
+	 * Associated address
+	 */
+	host_t *address;
+
+	/**
+	 * Netmask for address
+	 */
+	uint8_t netmask;
+		
+	/**
+	 * Size of the rings
+	 */
+	uint64_t ring_capacity;
+	
+	/**
+	 * Bool to indicate to a reader not using the event handles that
+	 * the tun device is getting closed
+	 */
+	bool close;
+	
+	/**
+	 *  Lock used for makeing sure the device is not destroyed while in use */
+	mutex_t *lock;
+};
+
+/**
+ * Dynamically load a library and find a function in it
+ *
+ * @param libname     Name of the library to load
+ * @param funcname    Name of the function to find
+ * @param m           Pointer to a module. On return this is set to the
+ *                    the handle to the loaded library. The caller must
+ *                    free it by calling FreeLibrary() if not NULL.
+ *
+ * @return            Pointer to the function
+ *                    NULL on error -- use GetLastError() to find the error code.
+ *
+ **/
+static void * find_function(const WCHAR *libname, const char *funcname, HMODULE *m)
+{
+	WCHAR libpath[MAX_PATH];
+	void *fptr = NULL;
+
+	/* Make sure the dll is loaded from the system32 folder */
+	if (!GetSystemDirectoryW(libpath, _countof(libpath)))
+	{
+		return NULL;
+	}
+
+	/* +1 for the path seperator '\' */
+	const size_t path_length = wcslen(libpath) + 1 + wcslen(libname);
+	if (path_length >= _countof(libpath))
+	{
+		SetLastError(ERROR_INSUFFICIENT_BUFFER);
+		return NULL;
+	}
+	wcscat_s(libpath, _countof(libpath), L"\\");
+	wcscat_s(libpath, _countof(libpath), libname);
+
+	*m = LoadLibraryW(libpath);
+	if (*m == NULL)
+	{
+		return NULL;
+	}
+	fptr = GetProcAddress(*m, funcname);
+	if (!fptr)
+	{
+		FreeLibrary(*m);
+		*m = NULL;
+		return NULL;
+	}
+	return fptr;
+}
+
+static inline bool ring_over_capacity(TUN_RING *ring, uint64_t ring_capacity)
+{
+	return ((ring->Head >= ring_capacity) || (ring->Tail >= ring_capacity));
+}
+
+static inline ULONG get_head(TUN_RING *ring)
+{
+	return (ULONG) __atomic_load_n(&ring->Head, __ATOMIC_RELAXED);
+}
+
+static inline ULONG get_tail(TUN_RING *ring)
+{
+	return (ULONG) __atomic_load_n(&ring->Tail, __ATOMIC_RELAXED);
+}
+
+/* This is likely broken (!!!) */
+static bool write_to_ring(TUN_RING *ring, chunk_t packet, uint64_t ring_capacity)
+{
+	/* Check if packet fits */
+	TUN_PACKET *tun_packet;
+	ULONG ring_tail;
+	/* TODO: if ring is full or over capacity, wait until wintun driver sends event */
+	if (ring_over_capacity(ring, ring_capacity))
+	{
+		DBG1(DBG_LIB, "RING is over capacity!");
+		return FALSE;
+	}
+	
+	uint64_t aligned_packet_size = TUN_PACKET_ALIGN(sizeof(TUN_PACKET_HEADER) + packet.len);
+	uint64_t buffer_space = TUN_WRAP_POSITION((ring->Head - ring->Tail - TUN_PACKET_ALIGNMENT), ring_capacity);
+	if (aligned_packet_size > buffer_space)
+	{
+		DBG1(DBG_LIB, "RING is full!");
+		return FALSE;
+	}
+	
+	/* copy packet size and data into ring */
+	tun_packet = (TUN_PACKET *)&(ring->Data[ring->Tail]);
+	tun_packet->Size = packet.len;
+	memcpy(tun_packet->Data, packet.ptr, packet.len);
+	
+	/* move ring tail */
+	ring_tail = TUN_WRAP_POSITION((ring->Tail + aligned_packet_size), ring_capacity);
+	__atomic_store(&ring->Tail, &ring_tail, __ATOMIC_RELAXED);
+	return TRUE;
+}
+
+static bool pop_from_ring(TUN_RING *ring, chunk_t *chunk_packet,
+						  uint64_t ring_capacity, bool *need_restart)
+{
+	uint32_t length;
+	ULONG ret;
+	size_t aligned_packet_size;
+	/* TODO: If ring is over capacity wait until event is sent */
+	TUN_PACKET *packet;
+	/* Ring is empty if head == tail */
+	if (get_head(ring) == get_tail(ring))
+	{
+		return FALSE;
+	}
+	if (ring_over_capacity(ring, ring_capacity))
+	{
+		DBG0(DBG_LIB, "RING is over capacity!");
+	}
+	length = TUN_WRAP_POSITION((ring->Tail - ring->Head), ring_capacity);
+	
+	if (length < sizeof(uint32_t))
+	{
+		DBG0(DBG_LIB, "RING contains incomplete packet header!");
+		*need_restart = TRUE;
+		return FALSE;
+	}
+
+	packet = (TUN_PACKET *)&(ring->Data[ring->Head]);
+	if (packet->Size > TUN_MAX_IP_PACKET_SIZE)
+	{
+		DBG0(DBG_LIB, "RING contains packet larger than TUN_MAX_IP_PACKET_SIZE!");
+		*need_restart = TRUE;
+		return FALSE;
+	}
+	
+	aligned_packet_size = TUN_PACKET_ALIGN(sizeof(TUN_PACKET_HEADER) + packet->Size);
+	if (aligned_packet_size > length)
+	{
+		DBG0(DBG_LIB, "Incomplete packet in send ring!");
+		*need_restart = TRUE;
+		return FALSE;
+	}
+
+	chunk_packet->ptr = malloc(packet->Size);
+	chunk_packet->len = packet->Size;
+	memcpy(chunk_packet->ptr, packet->Data, chunk_packet->len);
+	/* Do we need to memset here? */
+	/* memwipe(packet->Data, packet->Size); */
+	/* move ring head */
+	ret = TUN_WRAP_POSITION((ring->Head + aligned_packet_size), ring_capacity);
+	__atomic_store(&ring->Head, &ret, __ATOMIC_RELAXED);
+	return TRUE;
+}
+
+/* Restart the driver.
+ * FIXME: Need to somehow update all the device handles in use everywhere */
+void restart_driver(private_windows_wintun_device_t *this)
+{
+	
+}
+
+METHOD(tun_device_t, wintun_set_mtu, bool,
+	   private_windows_wintun_device_t *this, int mtu)
+{
+	return TRUE;
+}
+
+METHOD(tun_device_t, wintun_get_mtu, int,
+	   private_windows_wintun_device_t *this)
+{
+	return 1500;
+}
+
+/* On WIN32 we return the handle of the read ring (kernel space -> user space) */
+METHOD(tun_device_t, wintun_get_handle, HANDLE,
+	   private_windows_wintun_device_t *this)
+{
+	this->lock->lock(this->lock);
+	HANDLE eventhandle = this->rings->Send.TailMoved;
+	this->lock->unlock(this->lock);
+	return eventhandle;
+}
+
+METHOD(tun_device_t, wintun_write_packet, bool,
+	   private_windows_wintun_device_t *this, chunk_t packet)
+{
+	this->lock->lock(this->lock);
+	if (this->windows_close)
+	{
+		return FALSE;
+		this->lock->unlock(this->lock);
+	}
+	write_to_ring(this->rings->Receive.Ring, packet, this->ring_capacity);
+	if (__atomic_load_n(&this->rings->Receive.Ring->Alertable, __ATOMIC_RELAXED))
+	{
+		SetEvent(this->rings->Receive.TailMoved);
+	}
+	this->lock->unlock(this->lock);
+	return TRUE;
+}
+
+METHOD(tun_device_t, wintun_read_packet, bool, 
+	   private_windows_wintun_device_t *this, chunk_t *packet)
+{
+	bool need_restart = FALSE, success;
+	this->lock->lock(this->lock);
+	if (this->windows_close)
+	{
+		this->lock->unlock(this->lock);
+		return FALSE;
+	}
+	success = pop_from_ring(this->rings->Send.Ring,
+							packet, this->ring_capacity, &need_restart);
+	if (need_restart)
+	{
+		this->lock->unlock(this->lock);
+		restart_driver(this);
+		return FALSE;
+	}
+	this->lock->unlock(this->lock);
+	return success;
+	/*
+	if (!success)
+	{
+		__atomic_store_n(this->rings->Send.Ring->Alertable, TRUE, __ATOMIC_RELAXED); 
+		success = pop_from_ring(this->rings->Send.Ring, packet,
+								this->ring_capacity, &need_restart);
+		if (need_restart)
+		{
+			restart_driver(this);
+			return FALSE;
+		}
+		if (!success)
+		{
+			return FALSE;
+			WaitForSingleObject(this->rings->Send.TailMoved, INFINITE);
+			this->rings->Send.Ring->Alertable = FALSE;
+		}
+		this->rings->Send.Ring->Alertable = FALSE;
+		ResetEvent(this->rings->Send.TailMoved);
+	}
+	return TRUE; */
+}
+
+/* Bogus implementation because nobody should use this */
+METHOD(tun_device_t, wintun_get_name, char*,
+	   private_windows_wintun_device_t *this)
+{
+	/* Use Windows IP helper functions. */
+	return this->if_name;
+}
+
+/* Bogus implementation because nobody should use this */
+METHOD(tun_device_t, wintun_set_address, bool,
+	   private_windows_wintun_device_t *this,  host_t *addr, uint8_t netmask)
+{
+	/* Use Windows IP helper functions. */
+	return TRUE;
+}
+
+/* Bogus implementation because nobody should use this */
+METHOD(tun_device_t, wintun_get_address, host_t*,
+	   private_windows_wintun_device_t *this, uint8_t *netmask)
+{
+	/* Use Windows IP helper functions. */
+	return NULL;
+}
+
+METHOD(tun_device_t, wintun_up, bool,
+	   private_windows_wintun_device_t *this)
+{
+	/* Use Windows IP helper functions. The right struct is here: https://docs.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_if_row2 */
+	return TRUE;
+}
+
+/**
+ * Destroy the tun device
+ */
+METHOD(tun_device_t, wintun_destroy, void,
+	   private_windows_wintun_device_t *this)
+{
+	this->lock->lock(this->lock);
+	this->close = TRUE;
+	SetEvent(this->rings->Send.TailMoved);
+	CloseHandle(this->rings->Send.TailMoved);
+	CloseHandle(this->rings->Receive.TailMoved);
+	CloseHandle(this->tun_handle);
+	VirtualFree(this->rings->Send.Ring, 0, MEM_RELEASE);
+	VirtualFree(this->rings->Receive.Ring, 0, MEM_RELEASE);
+	VirtualFree(this->rings, 0, MEM_RELEASE);
+	this->lock->unlock(this->lock);
+	this->lock->destroy(this->lock);
+}
+
+/**
+ * Deletes existing strongSwan wintun devices
+ * @return	bool indicating if the routine encountered SetupDi errors not
+ *		(not if any devices were deleted)
+ */
+bool delete_existing_strongswan_wintun_devices()
+{
+	DBG1(DBG_LIB, "Deleting existing strongSwan wintun devices.");
+	/* Reimplementation of CreateInterface from wireguard */
+	char buf[512];
+	uint64_t index = 0;
+	DWORD required_length = 0, ret = 0;
+	/* Create an empty device info set for network adapter device class. */
+	SP_DEVINFO_DATA dev_info_data = {
+		.cbSize = sizeof(SP_DEVINFO_DATA)
+	};
+	
+	/* Get all currently existing network interfaces */
+	HDEVINFO dev_info_set = SetupDiGetClassDevsExA(
+		&GUID_DEVCLASS_NET,
+		NULL,
+		NULL,
+		DIGCF_PRESENT,
+		NULL,
+		NULL,
+		NULL);
+	if (dev_info_set == INVALID_HANDLE_VALUE || (ret=GetLastError()))
+	{
+		if (ret)
+		{
+			DBG1(DBG_LIB, "Failed to create device info list (SetupDiCreateDeviceInfoListExA): %s",
+				human_readable_error(buf, ret, sizeof(buf)));
+		}
+		else
+		{
+			DBG1(DBG_LIB, "Failed to create device info list (SetupDiCreateDeviceInfoListExA), dev_info_set has value INVALID_HANDLE_VALUE");
+		}
+		return FALSE;
+	}
+	
+	if (!dev_info_set)
+	{
+		DBG1(DBG_LIB, "Failed to create DeviceInfoList(SetupDiCreateDeviceInfoListExA): %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto delete_device_info_list;
+	} 
+	
+	for (index=0;;index++)
+	{
+		DBG3(DBG_LIB, "Running SetupDiEnumDeviceInfo.");
+		if (!SetupDiEnumDeviceInfo(
+			dev_info_set,
+			index,
+			&dev_info_data))
+		{
+			ret = GetLastError();
+			if (ret != ERROR_NO_MORE_ITEMS)
+			{
+				DBG1(DBG_LIB, "An error occured: %s", dlerror_mt(buf, sizeof(buf)));
+			}
+			break;
+		}
+		/* Check device ID */
+		if (!SetupDiGetDeviceInstanceIdA(
+			dev_info_set,
+			&dev_info_data,
+			buf,
+			sizeof(buf),
+			&required_length))
+		{
+			DBG1(DBG_LIB, "Failed to get device ID for index %d: %s",
+				index, dlerror_mt(buf, sizeof(buf)));
+		}
+		else
+		{
+			DBG2(DBG_LIB, "Retrieved Device ID: %s", buf);
+			if (strstr(buf, "STRONGSWAN"))
+			{
+				DBG1(DBG_LIB, "Removing device %s", buf);
+				/* Delete device */
+				SP_REMOVEDEVICE_PARAMS remove_device_params = {
+					.ClassInstallHeader = {
+						.cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+						.InstallFunction = DIF_REMOVE
+					},
+					.Scope = DI_REMOVEDEVICE_GLOBAL,
+					.HwProfile = 0
+				};
+				if (SetupDiSetClassInstallParams(
+					dev_info_set,
+					&dev_info_data,
+					&remove_device_params.ClassInstallHeader,
+					sizeof(remove_device_params)))
+				{
+					if (!SetupDiCallClassInstaller(
+						DIF_REMOVE,
+						dev_info_set,
+						&dev_info_data))
+					{
+						DBG1(DBG_LIB, "Failed to remove device (SetupDiCallClassInstaller): %s",
+							dlerror_mt(buf, sizeof(buf)));
+					}			
+				}
+				else
+				{
+					DBG1(DBG_LIB, "Failed to set class install params (SetupDiSetClassInstallParams): %s",
+						dlerror_mt(buf, sizeof(buf)));
+				}
+			}
+			else
+			{
+				DBG2(DBG_LIB, "Skipping device %s", buf);
+			}
+		}
+	}
+delete_device_info_list :
+	if (!SetupDiDestroyDeviceInfoList(dev_info_set))
+	{
+		DBG1(DBG_LIB, "Failed to delete device info set (SetupDiDestroyDeviceInfoList): %s",
+			dlerror_mt(buf, sizeof(buf)));
+	}
+	return TRUE;
+}
+
+/**
+ * Return the file path to the interface (Can be used with CreateFile)
+ */
+bool get_interface_path(char *device_id, char **buf)
+{
+	DBG2(DBG_LIB, "Looking for device ID %s", device_id);
+	uint32_t bufsize = 512;
+	GUID cpy;
+	*buf = calloc(bufsize, sizeof(char));
+	uint64_t tries = 0;
+
+	do {
+		sleep(1);
+		cpy = (GUID) GUID_INTERFACE_NET;
+		CONFIGRET ret = CM_Get_Device_Interface_List(
+			&cpy,
+			device_id,
+			*buf,
+			bufsize,
+			CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+		if (ret == CR_BUFFER_SMALL)
+		{
+			DBG1(DBG_LIB, "Buffer too small for CM_Get_Device_Interface_List. That shouldn't happen.");
+			return FALSE;
+		}
+		else if (ret)
+		{
+			DBG1(DBG_LIB, "Other return code: %d", ret);
+			return FALSE;
+		}
+		ret = strlen(*buf);
+		if (!ret)
+		{
+			DBG2(DBG_LIB, "Waiting for 1 second for device path to become "
+					"available; cfgmngr32 currently returns the device path as "
+					"empty string. Try number: %d.", tries++);
+		}
+		else
+		{
+			break;
+		}
+	}
+	while (TRUE);
+
+	return TRUE;
+}
+
+/**
+ * Create the tun device and configure it as stored in the registry.
+ *					Can be NULL to make the system choose one at random.
+ * @return char				deviceID of the device that was created.
+ */
+char *create_wintun(char *NetCfgInstanceId, size_t *NetCfgInstanceId_length)
+{
+	/* Reimplementation of CreateInterface from wireguard */
+	char className[MAX_CLASS_NAME_LEN], buf[512], ipconfig_value[512],
+		*device_id = NULL, *property_buffer = NULL;
+	uint64_t index = 0;
+	/* Timeout of 5000 ms for registry operations */
+	size_t registry_timeout = 5000;
+	DWORD property_buffer_length = 0, required_length = 0,
+		reg_value_type,
+		ipconfig_value_length = sizeof(ipconfig_value),
+		ret = 0;
+	DWORDLONG driver_version = 0;
+	HKEY reg_hkey = NULL;
+	LPWSTR temp_buf = NULL;
+	HMODULE libnewdev = NULL;
+
+	FILETIME driver_date = {
+		.dwHighDateTime = 0,
+		.dwLowDateTime = 0
+	};
+	memset(NetCfgInstanceId, 0, *NetCfgInstanceId_length);
+
+	/* Create an empty device info set for network adapter device class. */
+	SP_DEVINFO_DATA dev_info_data = {
+		.cbSize = sizeof(SP_DEVINFO_DATA)
+	};
+	SP_DRVINFO_DATA_A drv_info_data = {
+		.cbSize = sizeof(SP_DRVINFO_DATA_A)
+	};
+	SP_DEVINSTALL_PARAMS_A dev_install_params = {
+		.cbSize = sizeof(SP_DEVINSTALL_PARAMS_A)
+	};
+	SP_DRVINFO_DETAIL_DATA_A *drv_info_detail_data = malloc(sizeof(SP_DRVINFO_DETAIL_DATA_A));
+	memset(drv_info_detail_data, 0, sizeof(SP_DRVINFO_DETAIL_DATA_A));
+	drv_info_detail_data->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
+	
+	/* is this optimizable? */
+	HDEVINFO dev_info_set = SetupDiCreateDeviceInfoListExA(
+		&GUID_DEVCLASS_NET,
+		NULL,
+		NULL,
+		NULL);
+	if (dev_info_set == INVALID_HANDLE_VALUE)
+	{
+		DBG1(DBG_LIB, "Failed to create device info list (SetupDiCreateDeviceInfoListExA): dev_info_set is an invalid handle");
+		free(drv_info_detail_data);
+		return FALSE;
+	}
+		
+	if ((ret=GetLastError()))
+	{
+		DBG1(DBG_LIB, "Failed to create device info list (SetupDiCreateDeviceInfoListExA): %s",
+			human_readable_error(buf, ret, sizeof(buf)));
+		free(drv_info_detail_data);
+		return FALSE;			
+	}
+	/* wait 50 ms */
+	struct timespec ts;
+	
+	if (!dev_info_set)
+	{
+		DBG1(DBG_LIB, "Failed to create DeviceInfoList(SetupDiCreateDeviceInfoListExA): %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto delete_device_info_list;
+	}
+
+	if(!SetupDiClassNameFromGuidExA(
+		&GUID_DEVCLASS_NET,
+		className,
+		sizeof(className)-1,
+		&required_length,
+		NULL,
+		NULL))
+	{
+		DBG1(DBG_LIB, "Failed to translate GUID to class name (SetupDiClassNameFromGuidExA): %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto delete_device_info_list;
+	}
+
+	if (required_length > property_buffer_length)
+	{
+		property_buffer = calloc(required_length, 1);
+		property_buffer_length = required_length;
+		if (!SetupDiClassNameFromGuidExA(
+			&GUID_DEVCLASS_NET,
+			property_buffer,
+			property_buffer_length,
+			&required_length,
+			NULL,
+			NULL))
+		{
+			DBG1(DBG_LIB, "Failed to translate GUID to class name (SetupDiClassNameFromGuidExA): %s",
+				dlerror_mt(buf, sizeof(buf)));
+			goto delete_device_info_list;
+		}
+	}
+	//DBG0(DBG_LIB, "Got class name %s", property_buffer);
+	/* property_buffer now holds class name */
+	if (!SetupDiCreateDeviceInfo(
+		dev_info_set,
+		STRONGSWAN_WINTUN_DEVICE_ID,
+		&GUID_DEVCLASS_NET,
+		STRONGSWAN_WINTUN_INTERFACE_NAME,
+		NULL,
+		DICD_GENERATE_ID,
+		&dev_info_data))
+	{
+		DBG1(DBG_LIB, "Failed to create device info object: %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto delete_device_info_list;
+	}
+
+	// create device
+	// Set quiet install setQuietInstall
+	if(!SetupDiGetDeviceInstallParamsA(
+		dev_info_set,
+		&dev_info_data,
+		&dev_install_params))
+	{
+		DBG1(DBG_LIB, "Failed to create wintun interface at (SetupDiGetDeviceInstallParamsA): %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto delete_driver_info_list;
+	}
+
+	dev_install_params.Flags |= DI_QUIETINSTALL;
+
+	if(!SetupDiSetDeviceInstallParamsA(
+		dev_info_set,
+		&dev_info_data,
+		&dev_install_params))
+	{
+		DBG1(DBG_LIB, "Failed to set device install parameter (SetupDiSetDeviceInstallParamsA).");
+		goto delete_device_info_list;
+	}
+
+	// Set a device information element as the selected member of a device information set. SetupDiSetSelectedDevice
+	if(!SetupDiSetSelectedDevice(
+		dev_info_set,
+		&dev_info_data))
+	{
+		DBG1(DBG_LIB, "Failed to select device (SetupDiSetSelectedDevice).");
+		goto delete_device_info_list;
+	}
+
+	// Set Plug&Play device hardware ID property. SetupDiSetDeviceRegistryProperty
+
+	if(!SetupDiSetDeviceRegistryPropertyA(
+		dev_info_set,
+		&dev_info_data,
+		SPDRP_HARDWAREID,
+		WINTUN_COMPONENT_ID,
+		sizeof(WINTUN_COMPONENT_ID)))
+	{
+		DBG1(DBG_LIB, "Failed to set Plug&Play device hardware ID property.");
+		goto delete_device_info_list;
+	}
+
+	if(!SetupDiBuildDriverInfoList(
+		dev_info_set,
+		&dev_info_data,
+		SPDIT_COMPATDRIVER))
+	{
+		DBG1(DBG_LIB, "Failed to build driver info list (SetupDiBuildDriverInfoList).");
+		goto delete_device_info_list;
+	}
+	// Following this, DestroyDriverInfoList has to be called, too
+
+	// loop over members of dev_info_data using EnumDriverInfo and index
+	// loop over devices, search for newest driver version
+
+	for(index=0;;index++)
+	{
+		if(!SetupDiEnumDriverInfo(
+			dev_info_set,
+			&dev_info_data,
+			SPDIT_COMPATDRIVER,
+			index,
+			&drv_info_data))
+		{
+			ret = GetLastError();
+			if (ret == ERROR_NO_MORE_ITEMS)
+			{
+				// break and go on
+				break;
+			}
+			// Skip broken driver records
+			continue;
+		}
+		DBG1(DBG_LIB, "driver description: %s", drv_info_data.Description);
+		DBG1(DBG_LIB, "driver MfgName: %s", drv_info_data.MfgName);
+		DBG1(DBG_LIB, "driver provider name: %s", drv_info_data.ProviderName);
+		if(CompareFileTime(&drv_info_data.DriverDate, &driver_date) == 1)
+		{
+			/* Check if the device is compatible by checking the hardware IDs */
+			/** On my system, the underlying call to SetupDiGetDriverInfoDetailA
+			 * fails, so this is disabled for now.
+			*/
+			/* required_length = 0;
+			if(windows_get_driver_info_data_a(
+			dev_info_set,
+			&dev_info_data,
+			&drv_info_data,
+			&drv_info_detail_data,
+			&drv_info_detail_data_size,
+			&required_length)
+			{*/			
+			if(check_hardwareids(drv_info_detail_data) ||
+				strcaseeq(drv_info_data.Description, "Wintun Userspace Tunnel"))
+			{
+				if(SetupDiSetSelectedDriverA(dev_info_set, &dev_info_data, &drv_info_data))
+				{
+					DBG2(DBG_LIB, "Successfully Set driver of device %s for new wintun device",
+						windows_setupapi_get_friendly_name(buf, sizeof(buf), dev_info_set, &dev_info_data));
+					driver_version = drv_info_data.DriverVersion;
+					driver_date = drv_info_data.DriverDate;
+				}
+				else
+				{
+					DBG1(DBG_LIB, "Failed to set driver of device %s for new wintun device: %s",
+						windows_setupapi_get_friendly_name(buf, sizeof(buf), dev_info_set, &dev_info_data),
+						dlerror_mt(buf, sizeof(buf)));
+					continue;
+				}
+			}
+			else
+			{
+				DBG1(DBG_LIB, "No HardwareID match found");
+			}
+			/*} else {
+			DBG1(DBG_LIB, "Failed to get driver info data");
+			} */
+		}
+	}
+	if (driver_version == 0)
+	{
+		DBG1(DBG_LIB, "No driver installed for device: %s", dlerror_mt(buf, sizeof(buf)));
+		goto delete_driver_info_list;
+	}
+
+	/* Call appropriate class installer */
+	if (!SetupDiCallClassInstaller(
+		DIF_REGISTERDEVICE,
+		dev_info_set,
+		&dev_info_data))
+	{
+		DBG1(DBG_LIB, "SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed: %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto uninstall_device;
+	}
+
+	/* Install the device using DiInstallDevice()
+	 * We instruct the system to use the best driver in the driver store
+	 * by setting the drvinfo argument of DiInstallDevice as NULL. This
+	 * assumes a driver is already installed in the driver store.
+	 */
+#ifdef HAVE_DIINSTALLDEVICE
+	if (!DiInstallDevice(NULL, dev_info_set, &dev_info_data, NULL, 0, FALSE))
+#else
+	/* mingw does not resolve DiInstallDevice, so load it at run time. */
+	typedef BOOL (WINAPI *DiInstallDeviceFn)(HWND, HDEVINFO, SP_DEVINFO_DATA *,
+											 SP_DRVINFO_DATA *, DWORD, BOOL *);
+	DiInstallDeviceFn installfn = find_function(L"newdev.dll", "DiInstallDevice", &libnewdev);
+
+	if (!installfn)
+	{
+		DBG1(DBG_LIB, "Failed to locate DiInstallDevice(): %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto close_reg_key;
+	}
+
+	if (!installfn(NULL, dev_info_set, &dev_info_data, NULL, 0, FALSE))
+#endif
+	{
+		DBG1(DBG_LIB, "DiInstallDevice failed: %s",
+			dlerror_mt(buf, sizeof(buf)));
+		goto close_reg_key;
+	}
+
+	reg_hkey = SetupDiOpenDevRegKey(
+		dev_info_set,
+		&dev_info_data,
+		DICS_FLAG_GLOBAL,
+		0,
+		DIREG_DRV, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY);
+
+	if (!registry_wait_get_value(reg_hkey, NetCfgInstanceId, (DWORD *) NetCfgInstanceId_length,
+	   							 "NetCfgInstanceId", &reg_value_type, registry_timeout))
+	{
+		DBG1(DBG_LIB, "Failed to retrieve NetCfgInstanceId key. Aborting tun device installation.");
+		goto close_reg_key;
+	}
+	
+	RegCloseKey(reg_hkey);
+	
+	if (!(reg_value_type &= (REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ)))
+	{
+		DBG1(DBG_LIB, "Type of NetCfgInstanceId is not REG_SZ, REG_EXPAND_SZ or REG_MULTI_SZ (Meaning it is not a string). Aborting tun device install.");
+		goto close_reg_key;
+	}
+
+	/* tcpipAdapterRegKeyName */
+	ignore_result(snprintf(buf, sizeof(buf),
+				  "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%s",
+				  NetCfgInstanceId));
+	
+	// Wait for TCP/IP adapter registry key to emerge and populate.
+	// Wait for reg key to be populated
+	if(!(reg_hkey = registry_open_wait(HKEY_LOCAL_MACHINE, buf, 0, registry_timeout)))
+	{
+		DBG2(DBG_LIB, "Timeout while waiting for %s to be accessible.", buf);
+		goto close_reg_key;
+	}
+
+	/* IpConfig */
+	if(!registry_wait_get_value(reg_hkey, ipconfig_value, &ipconfig_value_length,
+								"IpConfig", &reg_value_type, registry_timeout))
+	{
+		DBG2(DBG_LIB, "Timeout while waiting for key %s\\%s", buf, "IpConfig");
+		goto close_reg_key;
+	}
+	RegCloseKey(reg_hkey);
+	
+	if (!(reg_value_type &= (REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ)))
+	{
+		DBG2(DBG_LIB, "Invalid type %u for key %s\\%s",
+			reg_value_type, buf, "IpConfig");
+		goto close_reg_key;
+	}
+	
+	/* tcpipInterfaceRegKeyName */
+	ignore_result(snprintf(buf, sizeof(buf),
+						   "SYSTEM\\CurrentControlSet\\Services\\%s",
+						   ipconfig_value));
+	
+	if(!(reg_hkey = registry_open_wait(HKEY_LOCAL_MACHINE, buf, 0, registry_timeout)))
+	{
+		DBG2(DBG_LIB, "Timeout while waiting for key %s to be accessible", buf);
+		goto close_reg_key;
+	}
+	
+	/* EnableDeadGWDetect */
+	ret = 0;
+	if((ret = RegSetValueExA(reg_hkey, "EnableDeadGWDetect", 0, REG_DWORD,
+							(BYTE *)&ret, sizeof(ret))) != ERROR_SUCCESS)
+	{
+		DBG1(DBG_LIB, "Failed to set EnableDeadGWDetect to 0 (%d): %s", ret,
+			human_readable_error(buf, ret, sizeof(buf)));
+	}
+	ret = sizeof(buf);
+	if ((ret = RegQueryValueExA(reg_hkey, "EnableDeadGWDetect", NULL, (LPDWORD) &index,
+							  buf, &ret)) != ERROR_SUCCESS)
+	{
+		DBG1(DBG_LIB, "Failed to retrieve type and value of EnableDeadGWDetect. Ret is %d", ret);
+	}
+	else
+	{
+		DBG2(DBG_LIB, "EnableDeadGWDetect is type %d with value %d", index, buf);
+	}
+
+	ret = 1;
+	/* Set interface metric for IPv4 (Different folder for IPv6) to 1 to make sure it is preferred for DNS resolution */
+	if((ret = RegSetValueExA(reg_hkey, "InterfaceMetric", 0, REG_DWORD,
+							 (BYTE *)&ret, sizeof(ret))) != ERROR_SUCCESS)
+	{
+		DBG1(DBG_LIB, "Failed to set InterfaceMetric to 1 (%d): %s", ret, human_readable_error(buf, ret, sizeof(buf)));
+	}
+
+	if(!SetupDiGetDeviceInstanceIdA(
+		dev_info_set,
+		&dev_info_data,
+		buf,
+		sizeof(buf),
+		&required_length))
+	{
+		DBG2(DBG_LIB, "Failed to get device ID for index %d: %s", index, dlerror_mt(buf, sizeof(buf)));
+	}
+
+	device_id = malloc(strlen(buf)+1);
+	memcpy(device_id, buf, strlen(buf)+1);
+	
+close_reg_key :
+	if (handle_is_valid(reg_hkey))
+	{
+		RegCloseKey(reg_hkey);
+	}
+
+delete_driver_info_list : ;
+	if (!device_id)
+	{
+		/* RemoveDeviceParams yade yade yada */
+uninstall_device : ;
+		/* SP_CLASSINSTALL_HEADER class_install_header = {
+			.cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+			.InstallFunction = DIF_REMOVE
+		}; */
+		SP_REMOVEDEVICE_PARAMS remove_device_params = {
+			.ClassInstallHeader = {
+				.cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+				.InstallFunction = DIF_REMOVE
+			},
+				.Scope = DI_REMOVEDEVICE_GLOBAL,
+				.HwProfile = 0
+		};
+		if (SetupDiSetClassInstallParams(
+			dev_info_set,
+			&dev_info_data,
+			&remove_device_params.ClassInstallHeader,
+			sizeof(remove_device_params)))
+		{
+			if (!SetupDiCallClassInstaller(
+				DIF_REMOVE,
+				dev_info_set,
+				&dev_info_data))
+			{
+				DBG2(DBG_LIB, "Failed to remove device (SetupDiCallClassInstaller): %s", dlerror_mt(buf, sizeof(buf)));
+			}			
+		}
+		else
+		{
+			DBG2(DBG_LIB, "Failed to set class install params (SetupDiSetClassInstallParams): %s", dlerror_mt(buf, sizeof(buf)));
+		}
+	}
+
+	if (!SetupDiDestroyDriverInfoList(
+		dev_info_set,
+		&dev_info_data,
+		SPDIT_COMPATDRIVER))
+	{
+		DBG2(DBG_LIB, "Failed to destroy driver info list (SetupDiDestroyDriverInfoList): %s", dlerror_mt(buf, sizeof(buf)));
+	}
+
+delete_device_info_list :
+	if (!SetupDiDestroyDeviceInfoList(dev_info_set))
+	{
+		DBG2(DBG_LIB, "Failed to delete device info set (SetupDiDestroyDeviceInfoList): %s", dlerror_mt(buf, sizeof(buf)));
+	}
+
+	if(device_id)
+	{
+		DBG2(DBG_LIB, "Successfully created a wintun device with NetCfgInstanceId %s", NetCfgInstanceId);
+	}
+	else
+	{
+		DBG2(DBG_LIB, "Failed to create a wintun device");
+	}
+
+	if (libnewdev)
+	{
+		FreeLibrary(libnewdev);		
+	}
+
+	return device_id;
+}
+
+bool impersonate_as_system()
+{
+	HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token;
+	PROCESSENTRY32 entry;
+	BOOL ret;
+	DWORD pid = 0;
+	TOKEN_PRIVILEGES privileges;
+
+	memset(&entry, 0 , sizeof(entry));
+	memset(&privileges, 0, sizeof(privileges));
+
+	entry.dwSize = sizeof(PROCESSENTRY32);
+
+	privileges.PrivilegeCount = 1;
+	privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED;
+
+	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
+	{
+		return false;
+	}
+
+	if (!ImpersonateSelf(SecurityImpersonation))
+	{
+		return false;
+	}
+
+	if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
+	{
+		RevertToSelf();
+		return false;
+	}
+	if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL))
+	{
+		CloseHandle(thread_token);
+		RevertToSelf();
+		return false;
+	}
+	CloseHandle(thread_token);
+
+	process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+	if (process_snapshot == INVALID_HANDLE_VALUE)
+	{
+		RevertToSelf();
+		return false;
+	}
+	for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry))
+	{
+		if (!_stricmp(entry.szExeFile, "winlogon.exe"))
+		{
+			pid = entry.th32ProcessID;
+			break;
+		}
+	}
+	CloseHandle(process_snapshot);
+	if (!pid)
+	{
+		RevertToSelf();
+		return false;
+	}
+
+	winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+	if (!winlogon_process)
+	{
+		RevertToSelf();
+		return false;
+	}
+
+	if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
+	{
+		CloseHandle(winlogon_process);
+		RevertToSelf();
+		return false;
+	}
+	CloseHandle(winlogon_process);
+
+	if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token))
+	{
+		CloseHandle(winlogon_token);
+		RevertToSelf();
+		return false;
+	}
+	CloseHandle(winlogon_token);
+
+	if (!SetThreadToken(NULL, duplicated_token))
+	{
+		CloseHandle(duplicated_token);
+		RevertToSelf();
+		return false;
+	}
+	CloseHandle(duplicated_token);
+
+	return true;
+}
+
+bool configure_wintun(private_windows_wintun_device_t *this, const char *name_tmpl)
+{
+	char buf[1024], NetCfgInstanceId[255], *interface_path = NULL, *device_id = NULL;
+	DWORD ret;
+	size_t NetCfgInstanceId_length = sizeof(NetCfgInstanceId);
+	if (!(device_id = create_wintun(NetCfgInstanceId, &NetCfgInstanceId_length)))
+	{
+		DBG0(DBG_LIB, "Failed to create new wintun device");
+		return FALSE;
+	}
+	ret = get_interface_path(device_id, &interface_path);
+	free(device_id);
+	if (!ret)
+	{
+		return FALSE;
+	}
+	DBG2(DBG_LIB, "Device path: %s", interface_path);
+
+	this->tun_handle = CreateFile(
+		interface_path, GENERIC_READ | GENERIC_WRITE,
+		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+		NULL, OPEN_EXISTING, 0, NULL);
+	if(this->tun_handle != INVALID_HANDLE_VALUE)
+	{
+		strncpy(this->if_name, NetCfgInstanceId, sizeof(this->if_name)-1);
+	}
+	else
+	{
+		DBG0(DBG_LIB, "Failed to open tun file handle %s: %s",
+			 interface_path, dlerror_mt(buf, sizeof(buf)));
+	}
+
+	//DBG0(DBG_LIB, "foo");
+
+	if(!this->tun_handle)
+	{
+		DBG0(DBG_LIB, "Failed to find an unused TUN device.");
+		return FALSE;
+	}
+	
+		/* Create structs for rings and the rings themselves */
+	this->rings = VirtualAlloc(NULL, sizeof(TUN_REGISTER_RINGS), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+	this->rings->Send.TailMoved = CreateEventA(NULL, FALSE, FALSE, NULL);
+	this->rings->Send.Ring = VirtualAlloc(NULL, sizeof(TUN_RING) + this->ring_capacity + WINTUN_RING_TRAILING_BYTES,
+		MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+	this->rings->Send.RingSize = sizeof(TUN_RING) + this->ring_capacity + WINTUN_RING_TRAILING_BYTES;
+	memwipe(this->rings->Send.Ring, sizeof(TUN_RING) + this->ring_capacity + WINTUN_RING_TRAILING_BYTES);
+	this->rings->Receive.TailMoved = CreateEventA(NULL, FALSE, FALSE, NULL);
+	this->rings->Receive.Ring = VirtualAlloc(NULL, sizeof(TUN_RING) + this->ring_capacity + WINTUN_RING_TRAILING_BYTES,
+		MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+	this->rings->Receive.RingSize = sizeof(TUN_RING) + this->ring_capacity + WINTUN_RING_TRAILING_BYTES;
+	memwipe(this->rings->Receive.Ring, sizeof(TUN_RING) + this->ring_capacity + WINTUN_RING_TRAILING_BYTES);
+	DBG2(DBG_LIB, "Ring capacity: %d", this->ring_capacity);
+	
+	/* Tell driver about the rings */
+	if (!impersonate_as_system())
+	{
+		DBG0(DBG_LIB, "Failed to impersonate as SYSTEM, make sure process is running under privileged account");
+	}
+	
+	if(!DeviceIoControl(this->tun_handle, TUN_IOCTL_REGISTER_RINGS, this->rings,
+						sizeof(*this->rings), NULL, 0, &ret, NULL))
+	{
+		DBG0(DBG_LIB, "failed to install rings: %s", dlerror_mt(buf, sizeof(buf)));
+		CloseHandle(this->rings->Receive.TailMoved);
+		CloseHandle(this->rings->Send.TailMoved);
+		if(this->rings->Send.Ring)
+		{
+			VirtualFree(this->rings->Send.Ring, 0, MEM_RELEASE);
+		}
+		if (this->rings->Receive.Ring)
+		{
+			VirtualFree(this->rings->Receive.Ring, 0, MEM_RELEASE);
+		}	 
+		VirtualFree(this->rings, 0, MEM_RELEASE);
+		CloseHandle(this->tun_handle);
+		if (!RevertToSelf())
+		{
+			DBG0(DBG_LIB, "RevertToSelf error: %s", dlerror_mt(buf, sizeof(buf)));
+		}
+		return FALSE;
+	}
+	if (!RevertToSelf())
+	{
+		DBG0(DBG_LIB, "RevertToSelf error: %s", dlerror_mt(buf, sizeof(buf)));
+	}	
+	return TRUE;
+}
+
+/* Stub. Returns an unused wintun device */
+GUID *find_unused_wintun_device(const char *name_tmpl)
+{
+	return NULL;
+}
+
+/* Stub. Returns the public interface of a fully configured wintun device */
+tun_device_t *initialize_unused_wintun_device(const char *name_tmpl)
+{
+	private_windows_wintun_device_t *this;
+	INIT(this,
+		.public = {
+			.read_packet = _wintun_read_packet,
+			.write_packet = _wintun_write_packet,
+			.get_mtu = _wintun_get_mtu,
+			.set_mtu = _wintun_set_mtu,
+			.get_name = _wintun_get_name,
+			.get_handle = _wintun_get_handle,
+			.set_address = _wintun_set_address,
+			.get_address = _wintun_get_address,
+			.up = _wintun_up,
+			.destroy = _wintun_destroy,
+		},
+		.lock = mutex_create(MUTEX_TYPE_DEFAULT),
+		.rings = NULL,
+		.tun_handle = NULL,
+		.ifindex = 0,
+		.ring_capacity = lib->settings->get_int(lib->settings,
+					"%s.ring_capacity", TUN_RING_CAPACITY, lib->ns),
+	);
+	if(configure_wintun(this, name_tmpl))
+	{
+		return &this->public;
+	}
+	else
+	{
+		this->lock->destroy(this->lock);
+		free(this);
+		return NULL;
+	}
+}
+
+/* Possibly creates, and configures a wintun device */
+tun_device_t *try_configure_wintun(const char *name_tmpl)
+{
+	if (lib->settings->get_bool(lib->settings, "%s.use_wintun", TRUE, lib->ns))
+	{
+		if (lib->settings->get_bool(lib->settings, "%s.delete_existing_wintun_devices", TRUE, lib->ns))
+		{
+			delete_existing_strongswan_wintun_devices();
+		}
+		tun_device_t *new_device = NULL;
+		new_device = initialize_unused_wintun_device(name_tmpl);
+		if (new_device)
+		{
+			return new_device;
+		}		
+	}
+	return NULL;
+}
\ В конце файла нет новой строки
diff -ruN strongswan-5.8.4/src/libstrongswan/networking/wintun_support.h strongswancont-5.8.4-svc/src/libstrongswan/networking/wintun_support.h
--- strongswan-5.8.4/src/libstrongswan/networking/wintun_support.h	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/networking/wintun_support.h	2022-12-08 11:10:58.503375000 +0300
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 thermi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+/* 
+ * File:   wintun_support.h
+ * Author: thermi
+ *
+ * Created on 12. Mai 2020, 23:04
+ */
+
+#ifndef WINTUN_SUPPORT_H
+#define WINTUN_SUPPORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "windows_tun.h"
+#include "tlhelp32.h"
+#include "securitybaseapi.h"
+	
+#define TUN_PACKET_ALIGNMENT 4
+#define TUN_RING_CAPACITY (16*1024*1024)
+#define TUN_MAX_IP_PACKET_SIZE 0xFFFF
+#define WINTUN_RING_TRAILING_BYTES 0x10000
+
+typedef struct _TUN_PACKET_HEADER {
+	uint32_t size;
+} TUN_PACKET_HEADER;
+
+typedef struct _TUN_PACKET {
+	ULONG Size;
+	UCHAR Data[TUN_MAX_IP_PACKET_SIZE];
+} TUN_PACKET;
+
+#define TUN_TRAILING_SIZE (sizeof(TUN_PACKET) + ((TUN_MAX_IP_PACKET_SIZE + \
+	(TUN_PACKET_ALIGNMENT - 1)) &~ (TUN_PACKET_ALIGNMENT - 1)) - \
+	TUN_PACKET_ALIGNMENT)
+
+typedef struct _TUN_RING {
+	volatile ULONG Head;
+	volatile ULONG Tail;
+	volatile LONG Alertable;
+	UCHAR Data[];
+} TUN_RING;
+
+typedef struct _TUN_REGISTER_RINGS {
+	struct {
+		ULONG RingSize;
+		TUN_RING *Ring;
+		HANDLE TailMoved;
+	} Send, Receive;
+	/* Send ring is for data from driver to application */
+	/* Receive ring is for data from application to driver */
+} TUN_REGISTER_RINGS;
+
+#define TUN_RING_SIZE (sizeof(TUN_RING) + TUN_RING_CAPACITY + 0x10000)
+
+/* capacity must be a power of two and between 128 kiB and 64 MiB */
+#define IFNAMSIZ 256
+
+#define PNP_INSTANCE_ID "{abcde}"
+#define WINTUN_COMPONENT_ID "Wintun"
+/* for use with SetDeviceRegistryPropertyString */
+#define STRONGSWAN_WINTUN_INTERFACE_NAME "strongSwan VPN adapter"
+#define STRONGSWAN_WINTUN_DEVICE_ID "STRONGSWAN"
+/* Randomly generated, globally unique GUID for the strongSwan VPN adapter*/
+const static GUID GUID_WINTUN_STRONGSWAN = { 0x1f1f4dd1L, 0xe4d8, 0x487d, { 0xb7, 0xd5, 0x24, 0x93, 0xb2, 0xce, 0x0c, 0x49 } };
+const static GUID GUID_INTERFACE_NET = {0xcac88484L, 0x7515, 0x4c03, {0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61}};
+
+const static char GUID_WINTUN_STRONGSWAN_STRING[] = "1f1f4dd1-e4d8-487d-b7d5-2493b2ce0c49";
+/* GUIDs from openvpn tun.c code */
+const static GUID GUID_DEVCLASS_NET = { 0x4d36e972L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
+#define TUN_IOCTL_REGISTER_RINGS 0xca6ce5c0
+//#define TUN_IOCTL_REGISTER_RINGS ((51820 << 16) | (0x970 << 2) | 0 /*METHOD_BUFFERED*/ | (0x3 /*FILE_READ_DATA | FILE_WRITE_DATA*/ << 14))
+#define TUN_PACKET_TRAILING_SIZE (sizeof(uint32_t) + ((TUN_MAX_IP_PACKET_SIZE + \
+	(TUN_PACKET_ALIGNMENT - 1)) &~(TUN_PACKET_ALIGNMENT - 1)) - TUN_PACKET_ALIGNMENT)
+#define TUN_WRAP_POSITION(position, size) ((position & (size - 1)))
+#define TUN_PACKET_ALIGN(size) ((size + (TUN_PACKET_ALIGNMENT - 1)) &~(TUN_PACKET_ALIGNMENT - 1))
+
+tun_device_t *try_configure_wintun(const char *name_tmpl);
+
+bool delete_existing_strongswan_wintun_devices();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WINTUN_SUPPORT_H */
\ В конце файла нет новой строки
diff -ruN strongswan-5.8.4/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c strongswancont-5.8.4-svc/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
--- strongswan-5.8.4/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c	2018-12-14 18:48:24.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c	2022-07-06 15:47:34.862985000 +0300
@@ -168,7 +168,7 @@
 	int i;
 	bool success = FALSE;
 
-	if (!params)
+	if (!params || params->salt_len < 0)
 	{
 		return FALSE;
 	}
diff -ruN strongswan-5.8.4/src/libstrongswan/plugins/openssl/openssl_crl.c strongswancont-5.8.4-svc/src/libstrongswan/plugins/openssl/openssl_crl.c
--- strongswan-5.8.4/src/libstrongswan/plugins/openssl/openssl_crl.c	2018-12-14 18:48:24.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/plugins/openssl/openssl_crl.c	2022-07-06 15:47:34.862985000 +0300
@@ -288,6 +288,7 @@
 	private_openssl_crl_t *this, certificate_t *issuer,
 	signature_params_t **scheme)
 {
+	chunk_t keyid = chunk_empty;
 	chunk_t fingerprint, tbs;
 	public_key_t *key;
 	x509_t *x509;
@@ -312,13 +313,31 @@
 	{
 		return FALSE;
 	}
+
+
+	if (this->authKeyIdentifier.ptr)
+	{
+		keyid = x509->get_subjectKeyIdentifier(x509);
+		if (keyid.len && !chunk_equals(keyid, this->authKeyIdentifier))
+		{
+			return FALSE;
+		}
+	}
+	if (!keyid.len)
+	{
+		if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
+		{
+			return FALSE;
+		}
+	}
+	/*
 	if (this->authKeyIdentifier.ptr && key)
 	{
 		if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) ||
 			!chunk_equals(fingerprint, this->authKeyIdentifier))
 		{
 			return FALSE;
-		}
+		}		
 	}
 	else
 	{
@@ -327,6 +346,8 @@
 			return FALSE;
 		}
 	}
+	*/
+
 	/* i2d_re_X509_CRL_tbs() was added with 1.1.0 when X509_CRL became opaque */
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
 	tbs = openssl_i2chunk(re_X509_CRL_tbs, this->crl);
diff -ruN strongswan-5.8.4/src/libstrongswan/plugins/openssl/openssl_x509.c strongswancont-5.8.4-svc/src/libstrongswan/plugins/openssl/openssl_x509.c
--- strongswan-5.8.4/src/libstrongswan/plugins/openssl/openssl_x509.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/plugins/openssl/openssl_x509.c	2022-07-06 15:47:34.862985000 +0300
@@ -1142,6 +1142,13 @@
 					chunk, BUILD_END);
 			free(chunk.ptr);
 			break;
+		case OID_BIGN_PUB_KEY:
+				chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509));
+				this->pubkey = lib->creds->create(lib->creds,
+					CRED_PUBLIC_KEY, KEY_BIGN, BUILD_BLOB_ASN1_DER,
+ 					chunk, BUILD_END);
+ 			free(chunk.ptr);
+ 			break;
 		default:
 			DBG1(DBG_LIB, "unsupported public key algorithm");
 			break;
diff -ruN strongswan-5.8.4/src/libstrongswan/plugins/test_vectors/test_vectors/rng.c strongswancont-5.8.4-svc/src/libstrongswan/plugins/test_vectors/test_vectors/rng.c
--- strongswan-5.8.4/src/libstrongswan/plugins/test_vectors/test_vectors/rng.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/plugins/test_vectors/test_vectors/rng.c	2023-05-15 14:37:42.918947000 +0300
@@ -44,7 +44,7 @@
 			}
 		}
 	}
-	DBG2(DBG_LIB, "  Monobit: %d/%d bits set", bits, data.len * 8);
+	DBG1(DBG_LIB, "  Monobit: %d/%d bits set", bits, data.len * 8);
 	if (bits > param->lower && bits < param->upper)
 	{
 		return TRUE;
@@ -101,7 +101,7 @@
 		sum += (counter[i] * counter[i]) / 5000.0 * 16.0;
 	}
 	sum -= 5000.0;
-	DBG2(DBG_LIB, "  Poker: %f", sum);
+	DBG1(DBG_LIB, "  Poker: %f", sum);
 	if (sum > param->lower && sum < param->upper)
 	{
 		return TRUE;
@@ -190,7 +190,7 @@
 		}
 	}
 
-	DBG2(DBG_LIB, "  Runs: zero: %d/%d/%d/%d/%d/%d, one: %d/%d/%d/%d/%d/%d, "
+	DBG1(DBG_LIB, "  Runs: zero: %d/%d/%d/%d/%d/%d, one: %d/%d/%d/%d/%d/%d, "
 		 "longruns: %d",
 		 zero_runs[1], zero_runs[2], zero_runs[3],
 		 zero_runs[4], zero_runs[5], zero_runs[6],
diff -ruN strongswan-5.8.4/src/libstrongswan/plugins/x509/x509_cert.c strongswancont-5.8.4-svc/src/libstrongswan/plugins/x509/x509_cert.c
--- strongswan-5.8.4/src/libstrongswan/plugins/x509/x509_cert.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/plugins/x509/x509_cert.c	2023-06-15 16:21:26.117463000 +0300
@@ -202,6 +202,11 @@
 	x509_flag_t flags;
 
 	/**
+	 * x509 key usage
+	 */
+	x509_key_usage_t keyUsage;
+
+	/**
 	 * Signature scheme
 	 */
 	signature_params_t *scheme;
@@ -736,18 +741,33 @@
 					{
 						case KU_CRL_SIGN:
 							this->flags |= X509_CRL_SIGN;
+							this->keyUsage |= X509_KU_CRL_SIGN;
+							break;
+						case KU_KEY_CERT_SIGN:
+							/* we use the caBasicConstraint, MUST be set */
+							this->keyUsage |= X509_KU_KEY_CERT_SIGN;							
 							break;
 						case KU_DIGITAL_SIGNATURE:
+							this->keyUsage |= X509_KU_DIGITAL_SIGNATURE;
+							break;
 						case KU_NON_REPUDIATION:
 							this->flags |= X509_IKE_COMPLIANT;
-							break;
-						case KU_KEY_CERT_SIGN:
-							/* we use the caBasicConstraint, MUST be set */
+							this->keyUsage |= X509_KU_NON_REPUDIATION;
+							break;						
 						case KU_KEY_ENCIPHERMENT:
+							this->keyUsage |= X509_KU_KEY_ENCIPHERMENT;
+							break;
 						case KU_DATA_ENCIPHERMENT:
+							this->keyUsage |= X509_KU_DATA_ENCIPHERMENT;
+							break;
 						case KU_KEY_AGREEMENT:
+							this->keyUsage |= X509_KU_KEY_AGREEMENT;
+							break;
 						case KU_ENCIPHER_ONLY:
+							this->keyUsage |= X509_KU_ENCIPHER_ONLY;
+							break;
 						case KU_DECIPHER_ONLY:
+							this->keyUsage |= X509_KU_DECIPHER_ONLY;
 							break;
 					}
 				}
@@ -1830,6 +1850,12 @@
 	return this->flags;
 }
 
+METHOD(x509_t, get_keyUsage, x509_key_usage_t,
+	private_x509_cert_t *this)
+{
+	return this->keyUsage;
+}
+
 METHOD(x509_t, get_serial, chunk_t,
 	private_x509_cert_t *this)
 {
@@ -1846,7 +1872,6 @@
 	else
 	{
 		chunk_t fingerprint;
-
 		if (this->public_key->get_fingerprint(this->public_key,
 									KEYID_PUBKEY_SHA1, &fingerprint))
 		{
@@ -1992,6 +2017,7 @@
 					.destroy = _destroy,
 				},
 				.get_flags = _get_flags,
+				.get_keyUsage = _get_keyUsage,
 				.get_serial = _get_serial,
 				.get_subjectKeyIdentifier = _get_subjectKeyIdentifier,
 				.get_authKeyIdentifier = _get_authKeyIdentifier,
@@ -2043,6 +2069,9 @@
 		case ID_DER_ASN1_DN:
 			context = ASN1_CONTEXT_C_4;
 			break;
+		case ID_DER_ASN1_GN_URI:
+			context = ASN1_CONTEXT_S_6;
+			break;
 		case ID_IPV4_ADDR:
 		case ID_IPV6_ADDR:
 			context = ASN1_CONTEXT_S_7;
@@ -2319,11 +2348,16 @@
 												chunk_from_chars(0xFF)),
 											pathLenConstraint)));
 		/* set CertificateSign and implicitly CRLsign */
-		keyUsageBits = keyUsageCertSignCrlSign;
+		//keyUsageBits = keyUsageCertSignCrlSign;
+		keyUsageBits = chunk_from_chars(0x01, 0x06);
+		cert->keyUsage |= X509_KU_KEY_CERT_SIGN;
+		cert->keyUsage |= X509_KU_CRL_SIGN;
 	}
 	else if (cert->flags & X509_CRL_SIGN)
 	{
-		keyUsageBits = keyUsageCrlSign;
+		//keyUsageBits = keyUsageCrlSign;
+		keyUsageBits = chunk_from_chars(0x01, 0x02);
+		cert->keyUsage |= X509_KU_CRL_SIGN;
 	}
 	if (keyUsageBits.len)
 	{
@@ -2367,8 +2401,9 @@
 										ocspSigning, msSmartcardLogon)));
 	}
 
-	/* add subjectKeyIdentifier to CA and OCSP signer certificates */
-	if (cert->flags & (X509_CA | X509_OCSP_SIGNER | X509_CRL_SIGN))
+	/* add subjectKeyIdentifier to CA and OCSP signer certificates and BIGN certificates */
+	if ((cert->flags & (X509_CA | X509_OCSP_SIGNER | X509_CRL_SIGN)) ||
+		(cert->public_key->get_type(cert->public_key) == KEY_BIGN))
 	{
 		chunk_t keyid;
 
diff -ruN strongswan-5.8.4/src/libstrongswan/plugins/x509/x509_pkcs10.c strongswancont-5.8.4-svc/src/libstrongswan/plugins/x509/x509_pkcs10.c
--- strongswan-5.8.4/src/libstrongswan/plugins/x509/x509_pkcs10.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/plugins/x509/x509_pkcs10.c	2023-06-12 16:07:13.535787000 +0300
@@ -24,6 +24,7 @@
 #include <credentials/keys/private_key.h>
 #include <collections/linked_list.h>
 #include <utils/identification.h>
+#include <time.h>
 
 typedef struct private_x509_pkcs10_t private_x509_pkcs10_t;
 
@@ -72,6 +73,11 @@
 	chunk_t challengePassword;
 
 	/**
+	 * certificate validity
+	 */
+	chunk_t certificateValidity;
+
+	/**
 	 * Signature scheme
 	 */
 	signature_params_t *scheme;
@@ -95,6 +101,16 @@
 	 * reference count
 	 */
 	refcount_t ref;
+
+	/**
+	 * validity starts
+	 */
+	time_t notBefore;
+
+	/**
+	 * validity ends
+	 */
+	time_t notAfter;
 };
 
 /**
@@ -481,6 +497,7 @@
 		{	/* only parsed certificate requests point these fields to "encoded" */
 			chunk_free(&this->certificationRequestInfo);
 			chunk_free(&this->challengePassword);
+			chunk_free(&this->certificateValidity);
 			chunk_free(&this->signature);
 		}
 		free(this);
@@ -522,15 +539,77 @@
 	return this;
 }
 
+
+static chunk_t build_msExtensions(private_x509_pkcs10_t *cert, bool is78,
+								  chunk_t *subjectAltNames, chunk_t *certificatePolicies)
+{
+	chunk_t extensions = chunk_empty;
+
+	chunk_t subjectKeyId = chunk_empty;
+	chunk_t keyUsage = chunk_empty;	
+//	chunk_t basicConstraints = chunk_empty;
+
+	chunk_t keyId = chunk_empty;
+	
+	if(!cert->public_key->get_fingerprint(cert->public_key, KEYID_PUBKEY_BELT, &keyId))
+	{
+		DBG1(DBG_CNT, "unable to get public key identifier");
+		return extensions;
+	}
+
+	subjectKeyId = asn1_wrap(ASN1_SEQUENCE, "mm",
+					asn1_build_known_oid(OID_SUBJECT_KEY_ID),
+					asn1_wrap(ASN1_OCTET_STRING, "m",
+						asn1_wrap(ASN1_OCTET_STRING, "m", keyId)));
+
+	keyUsage = asn1_wrap(ASN1_SEQUENCE, "mmm",
+					asn1_build_known_oid(OID_KEY_USAGE),
+					asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
+					asn1_wrap(ASN1_OCTET_STRING, "m",
+						asn1_wrap(ASN1_BIT_STRING, "c",
+							chunk_from_chars(0x05, 0xE0))));
+
+//	basicConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm",
+//							asn1_build_known_oid(OID_BASIC_CONSTRAINTS),
+//							asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
+//							asn1_wrap(ASN1_OCTET_STRING, "m",
+//								asn1_wrap(ASN1_SEQUENCE, "")));
+
+	int exts_request_oid = OID_MS_CERTIFICATE_EXTENSIONS;
+	if (is78)
+	{
+		exts_request_oid = OID_EXTENSION_REQUEST;
+	}
+	extensions = asn1_wrap(ASN1_SEQUENCE, "mm",
+					asn1_build_known_oid(exts_request_oid),
+					asn1_wrap(ASN1_SET, "m",
+						asn1_wrap(ASN1_SEQUENCE, "mmmm",
+//						asn1_wrap(ASN1_SEQUENCE, "mmmmm",
+							subjectKeyId,
+							keyUsage,
+							*certificatePolicies,
+//							basicConstraints,
+							*subjectAltNames)));
+
+	return extensions;
+}
+
+#define YEAR_SEC 365 * 24 * 60 * 60
+
+#define BPKI_MASK_VALIDITY            0x0F
+#define BPKI_MASK_GOVPKI              0x10
+#define BPKI_MASK_78_EXTS_REQUEST_OID 0x20
+
 /**
  * Generate and sign a new certificate request
  */
-static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
-					 int digest_alg)
+static bool generate(private_x509_pkcs10_t *cert, bool bpki, uint8_t flags,
+					 private_key_t *sign_key, int digest_alg)
 {
 	chunk_t key_info, subjectAltNames, attributes;
-	chunk_t extensionRequest  = chunk_empty;
-	chunk_t challengePassword = chunk_empty, sig_scheme = chunk_empty;
+	chunk_t extensionRequest  = chunk_empty, challengePassword = chunk_empty;
+	chunk_t certificateValidity = chunk_empty, sig_scheme = chunk_empty;
+	chunk_t certificatePolicies = chunk_empty;
 	identification_t *subject;
 
 	subject = cert->subject;
@@ -564,13 +643,63 @@
 	/* encode subjectAltNames */
 	subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames);
 
-	if (subjectAltNames.ptr)
+	if (bpki)
 	{
-		extensionRequest = asn1_wrap(ASN1_SEQUENCE, "mm",
-					asn1_build_known_oid(OID_EXTENSION_REQUEST),
-					asn1_wrap(ASN1_SET, "m",
-						asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames)
-					));
+		// certificate validity
+		uint8_t years = flags & BPKI_MASK_VALIDITY;
+		if (years > 0 && years <= 3)
+		{
+			cert->notBefore = time(NULL);
+			cert->notAfter = cert->notBefore + (YEAR_SEC*years);
+
+			certificateValidity = asn1_wrap(ASN1_SEQUENCE, "mm",
+					asn1_build_known_oid(OID_BPKI_AT_CERTIFICATE_VALIDITY),
+					asn1_wrap(ASN1_SEQUENCE, "mm",
+						asn1_from_time(&cert->notBefore, ASN1_UTCTIME),
+						asn1_from_time(&cert->notAfter, ASN1_UTCTIME)));
+		}
+
+		// certificate policies
+		if (flags & BPKI_MASK_GOVPKI)
+		{
+			certificatePolicies = asn1_wrap(ASN1_SEQUENCE, "mm",
+							asn1_build_known_oid(OID_CERTIFICATE_POLICIES),
+							asn1_wrap(ASN1_OCTET_STRING, "m",
+								asn1_wrap(ASN1_SEQUENCE, "mm", 
+									asn1_wrap(ASN1_SEQUENCE, "m",
+										asn1_build_known_oid(OID_BPKI_ROLE_ACD)),
+									asn1_wrap(ASN1_SEQUENCE, "m",
+										asn1_build_known_oid(OID_GOVPKI_CA2_TECHCERT)))));
+
+		}
+		else
+		{
+			certificatePolicies = asn1_wrap(ASN1_SEQUENCE, "mm",
+							asn1_build_known_oid(OID_CERTIFICATE_POLICIES),
+							asn1_wrap(ASN1_OCTET_STRING, "m",
+								asn1_wrap(ASN1_SEQUENCE, "m",
+									asn1_wrap(ASN1_SEQUENCE, "m",
+										asn1_build_known_oid(OID_BPKI_ROLE_ACD)))));
+		}
+
+		extensionRequest = build_msExtensions(cert, flags & BPKI_MASK_78_EXTS_REQUEST_OID,
+											  &subjectAltNames, &certificatePolicies);
+		if(!extensionRequest.ptr)
+		{
+			chunk_free(&sig_scheme);
+			return FALSE;
+		}
+	}
+	else
+	{
+		if (subjectAltNames.ptr)
+		{
+			extensionRequest = asn1_wrap(ASN1_SEQUENCE, "mm",
+						asn1_build_known_oid(OID_EXTENSION_REQUEST),
+						asn1_wrap(ASN1_SET, "m",
+							asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames)
+						));
+		}
 	}
 	if (cert->challengePassword.len > 0)
 	{
@@ -584,8 +713,11 @@
 					)
 			);
 	}
-	attributes = asn1_wrap(ASN1_CONTEXT_C_0, "mm", extensionRequest,
-												   challengePassword);
+
+	attributes = asn1_wrap(ASN1_CONTEXT_C_0, "mmm",
+					challengePassword,
+					extensionRequest,
+					certificateValidity);
 
 	cert->certificationRequestInfo = asn1_wrap(ASN1_SEQUENCE, "ccmm",
 							ASN1_INTEGER_0,
@@ -604,6 +736,7 @@
 							   cert->certificationRequestInfo,
 							   sig_scheme,
 							   asn1_bitstring("c", cert->signature));
+
 	return TRUE;
 }
 
@@ -652,6 +785,8 @@
 	private_x509_pkcs10_t *cert;
 	private_key_t *sign_key = NULL;
 	hash_algorithm_t digest_alg = HASH_SHA1;
+	bool bpki = FALSE;
+	uint8_t flags = 0;
 
 	cert = create_empty();
 	while (TRUE)
@@ -691,6 +826,24 @@
 			case BUILD_DIGEST_ALG:
 				digest_alg = va_arg(args, int);
 				continue;
+			case BUILD_BPKI_PKCS10:
+				bpki = (va_arg(args, int));
+				continue;
+			case BUILD_CERT_VALIDITY:
+				flags |= ((va_arg(args, int)) & BPKI_MASK_VALIDITY);
+				continue;
+			case BUILD_POLICY_GOVPKI:
+				if(va_arg(args, int))
+				{
+					flags |= BPKI_MASK_GOVPKI;					
+				}
+				continue;
+			case BUILD_78_EXTS_REQUEST_OID:
+				if(va_arg(args, int))
+				{
+					flags |= BPKI_MASK_78_EXTS_REQUEST_OID;					
+				}
+				continue;
 			case BUILD_END:
 				break;
 			default:
@@ -700,10 +853,11 @@
 		break;
 	}
 
-	if (sign_key && generate(cert, sign_key, digest_alg))
+	if (sign_key && generate(cert, bpki, flags, sign_key, digest_alg))
 	{
 		return &cert->public;
 	}
+
 	destroy(cert);
 	return NULL;
 }
diff -ruN strongswan-5.8.4/src/libstrongswan/processing/scheduler.c strongswancont-5.8.4-svc/src/libstrongswan/processing/scheduler.c
--- strongswan-5.8.4/src/libstrongswan/processing/scheduler.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/processing/scheduler.c	2022-07-06 15:47:35.518995000 +0300
@@ -94,30 +94,6 @@
 };
 
 /**
- * Compares two timevals, return >0 if a > b, <0 if a < b and =0 if equal
- */
-static int timeval_cmp(timeval_t *a, timeval_t *b)
-{
-	if (a->tv_sec > b->tv_sec)
-	{
-		return 1;
-	}
-	if (a->tv_sec < b->tv_sec)
-	{
-		return -1;
-	}
-	if (a->tv_usec > b->tv_usec)
-	{
-		return 1;
-	}
-	if (a->tv_usec < b->tv_usec)
-	{
-		return -1;
-	}
-	return 0;
-}
-
-/**
  * Returns the top event without removing it. Returns NULL if the heap is empty.
  */
 static event_t *peek_event(private_scheduler_t *this)
@@ -144,21 +120,22 @@
 
 	if (--this->event_count > 1)
 	{
-		/* seep down the top event */
 		u_int position = 1;
+
+		/* seep down the top event */
 		while ((position << 1) <= this->event_count)
 		{
 			u_int child = position << 1;
 
 			if ((child + 1) <= this->event_count &&
-				timeval_cmp(&this->heap[child + 1]->time,
-							&this->heap[child]->time) < 0)
+				timercmp(&this->heap[child + 1]->time,
+						 &this->heap[child]->time, <))
 			{
 				/* the "right" child is smaller */
 				child++;
 			}
 
-			if (timeval_cmp(&top->time, &this->heap[child]->time) <= 0)
+			if (!timercmp(&top->time, &this->heap[child]->time, >))
 			{
 				/* the top event fires before the smaller of the two children,
 				 * stop */
@@ -189,7 +166,7 @@
 
 	if ((event = peek_event(this)) != NULL)
 	{
-		if (timeval_cmp(&now, &event->time) >= 0)
+		if (!timercmp(&now, &event->time, <))
 		{
 			remove_event(this);
 			this->mutex->unlock(this->mutex);
@@ -262,8 +239,8 @@
 	position = this->event_count;
 
 	/* then bubble it up */
-	while (position > 1 && timeval_cmp(&this->heap[position >> 1]->time,
-									   &event->time) > 0)
+	while (position > 1 &&
+		   timercmp(&this->heap[position >> 1]->time, &event->time, >))
 	{
 		/* parent has to be fired after the new event, move up */
 		this->heap[position] = this->heap[position >> 1];
diff -ruN strongswan-5.8.4/src/libstrongswan/tests/suites/test_crypter.c strongswancont-5.8.4-svc/src/libstrongswan/tests/suites/test_crypter.c
--- strongswan-5.8.4/src/libstrongswan/tests/suites/test_crypter.c	2019-08-27 16:27:26.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/tests/suites/test_crypter.c	2022-07-06 15:47:35.566996000 +0300
@@ -34,6 +34,11 @@
 	{ OID_AES128_CBC, ENCR_AES_CBC, 128 },
 	{ OID_AES192_CBC, ENCR_AES_CBC, 192 },
 	{ OID_AES256_CBC, ENCR_AES_CBC, 256 },
+	{ OID_GOST28147_CTR, ENCR_GOST28147_CTR, 256 },
+	{ OID_GOST28147_CFB, ENCR_GOST28147_CFB, 256 },
+	{ OID_BELT_CBC, ENCR_BELT_CBC, 256 },
+	{ OID_BELT_CFB, ENCR_BELT_CFB, 256 },
+	{ OID_BELT_CTR, ENCR_BELT_CTR, 256 },
 	{ OID_CAMELLIA128_CBC, ENCR_CAMELLIA_CBC, 128 },
 	{ OID_CAMELLIA192_CBC, ENCR_CAMELLIA_CBC, 192 },
 	{ OID_CAMELLIA256_CBC, ENCR_CAMELLIA_CBC, 256 },
diff -ruN strongswan-5.8.4/src/libstrongswan/tests/suites/test_hasher.c strongswancont-5.8.4-svc/src/libstrongswan/tests/suites/test_hasher.c
--- strongswan-5.8.4/src/libstrongswan/tests/suites/test_hasher.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/tests/suites/test_hasher.c	2022-07-06 15:47:35.518995000 +0300
@@ -35,39 +35,40 @@
 	{ OID_SHA256, HASH_SHA256, KEY_ANY },                          /*  4 */
 	{ OID_SHA384, HASH_SHA384, KEY_ANY },                          /*  5 */
 	{ OID_SHA512, HASH_SHA512, KEY_ANY },                          /*  6 */
-	{ OID_SHA3_224, HASH_SHA3_224, KEY_ANY },                      /*  7 */
-	{ OID_SHA3_256, HASH_SHA3_256, KEY_ANY },                      /*  8 */
-	{ OID_SHA3_384, HASH_SHA3_384, KEY_ANY },                      /*  9 */
-	{ OID_SHA3_512, HASH_SHA3_512, KEY_ANY },                      /* 10 */
-	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ANY },                        /* 11 */
-	{ OID_MD2_WITH_RSA, HASH_MD2, KEY_RSA },                       /* 12 */
-	{ OID_MD5_WITH_RSA, HASH_MD5, KEY_RSA },                       /* 13 */
-	{ OID_SHA1_WITH_RSA, HASH_SHA1, KEY_RSA },                     /* 14 */
-	{ OID_SHA224_WITH_RSA, HASH_SHA224, KEY_RSA },                 /* 15 */
-	{ OID_SHA256_WITH_RSA, HASH_SHA256, KEY_RSA },                 /* 16 */
-	{ OID_SHA384_WITH_RSA, HASH_SHA384, KEY_RSA },                 /* 17 */
-	{ OID_SHA512_WITH_RSA, HASH_SHA512, KEY_RSA },                 /* 18 */
-	{ OID_RSASSA_PKCS1V15_WITH_SHA3_224, HASH_SHA3_224, KEY_RSA }, /* 19 */
-	{ OID_RSASSA_PKCS1V15_WITH_SHA3_256, HASH_SHA3_256, KEY_RSA }, /* 20 */
-	{ OID_RSASSA_PKCS1V15_WITH_SHA3_384, HASH_SHA3_384, KEY_RSA }, /* 21 */
-	{ OID_RSASSA_PKCS1V15_WITH_SHA3_512, HASH_SHA3_512, KEY_RSA }, /* 22 */
-	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_RSA },                        /* 23 */
-	{ OID_ED25519, HASH_IDENTITY, KEY_ED25519 },                   /* 24 */
-	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ED25519 },                    /* 25 */
-	{ OID_ED448, HASH_IDENTITY, KEY_ED448 },                       /* 26 */
-	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ED448 },                      /* 27 */
-	{ OID_ECDSA_WITH_SHA1, HASH_SHA1, KEY_ECDSA },                 /* 28 */
-	{ OID_ECDSA_WITH_SHA256, HASH_SHA256, KEY_ECDSA },             /* 29 */
-	{ OID_ECDSA_WITH_SHA384, HASH_SHA384, KEY_ECDSA },             /* 30 */
-	{ OID_ECDSA_WITH_SHA512, HASH_SHA512, KEY_ECDSA },             /* 31 */
-	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ECDSA },                      /* 32 */
-	{ OID_BLISS_WITH_SHA2_256, HASH_SHA256, KEY_BLISS },           /* 33 */
-	{ OID_BLISS_WITH_SHA2_384, HASH_SHA384, KEY_BLISS },           /* 34 */
-	{ OID_BLISS_WITH_SHA2_512, HASH_SHA512, KEY_BLISS },           /* 35 */
-	{ OID_BLISS_WITH_SHA3_256, HASH_SHA3_256, KEY_BLISS },         /* 36 */
-	{ OID_BLISS_WITH_SHA3_384, HASH_SHA3_384, KEY_BLISS },         /* 37 */
-	{ OID_BLISS_WITH_SHA3_512, HASH_SHA3_512, KEY_BLISS },         /* 38 */
-	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_BLISS },                      /* 39 */
+	{ OID_BELT_HASH, BELT_HASH, KEY_ANY },                         /*  7 */
+	{ OID_SHA3_224, HASH_SHA3_224, KEY_ANY },                      /*  8 */
+	{ OID_SHA3_256, HASH_SHA3_256, KEY_ANY },                      /*  9 */
+	{ OID_SHA3_384, HASH_SHA3_384, KEY_ANY },                      /* 10 */
+	{ OID_SHA3_512, HASH_SHA3_512, KEY_ANY },                      /* 11 */
+	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ANY },                        /* 12 */
+	{ OID_MD2_WITH_RSA, HASH_MD2, KEY_RSA },                       /* 13 */
+	{ OID_MD5_WITH_RSA, HASH_MD5, KEY_RSA },                       /* 14 */
+	{ OID_SHA1_WITH_RSA, HASH_SHA1, KEY_RSA },                     /* 15 */
+	{ OID_SHA224_WITH_RSA, HASH_SHA224, KEY_RSA },                 /* 16 */
+	{ OID_SHA256_WITH_RSA, HASH_SHA256, KEY_RSA },                 /* 17 */
+	{ OID_SHA384_WITH_RSA, HASH_SHA384, KEY_RSA },                 /* 18 */
+	{ OID_SHA512_WITH_RSA, HASH_SHA512, KEY_RSA },                 /* 19 */
+	{ OID_RSASSA_PKCS1V15_WITH_SHA3_224, HASH_SHA3_224, KEY_RSA }, /* 20 */
+	{ OID_RSASSA_PKCS1V15_WITH_SHA3_256, HASH_SHA3_256, KEY_RSA }, /* 21 */
+	{ OID_RSASSA_PKCS1V15_WITH_SHA3_384, HASH_SHA3_384, KEY_RSA }, /* 22 */
+	{ OID_RSASSA_PKCS1V15_WITH_SHA3_512, HASH_SHA3_512, KEY_RSA }, /* 23 */
+	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_RSA },                        /* 24 */
+	{ OID_ED25519, HASH_IDENTITY, KEY_ED25519 },                   /* 25 */
+	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ED25519 },                    /* 26 */
+	{ OID_ED448, HASH_IDENTITY, KEY_ED448 },                       /* 27 */
+	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ED448 },                      /* 28 */
+	{ OID_ECDSA_WITH_SHA1, HASH_SHA1, KEY_ECDSA },                 /* 29 */
+	{ OID_ECDSA_WITH_SHA256, HASH_SHA256, KEY_ECDSA },             /* 30 */
+	{ OID_ECDSA_WITH_SHA384, HASH_SHA384, KEY_ECDSA },             /* 31 */
+	{ OID_ECDSA_WITH_SHA512, HASH_SHA512, KEY_ECDSA },             /* 32 */
+	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_ECDSA },                      /* 33 */
+	{ OID_BLISS_WITH_SHA2_256, HASH_SHA256, KEY_BLISS },           /* 34 */
+	{ OID_BLISS_WITH_SHA2_384, HASH_SHA384, KEY_BLISS },           /* 35 */
+	{ OID_BLISS_WITH_SHA2_512, HASH_SHA512, KEY_BLISS },           /* 36 */
+	{ OID_BLISS_WITH_SHA3_256, HASH_SHA3_256, KEY_BLISS },         /* 37 */
+	{ OID_BLISS_WITH_SHA3_384, HASH_SHA3_384, KEY_BLISS },         /* 38 */
+	{ OID_BLISS_WITH_SHA3_512, HASH_SHA3_512, KEY_BLISS },         /* 39 */
+	{ OID_UNKNOWN, HASH_UNKNOWN, KEY_BLISS },                      /* 40 */
 
 };
 
diff -ruN strongswan-5.8.4/src/libstrongswan/threading/mutex.c strongswancont-5.8.4-svc/src/libstrongswan/threading/mutex.c
--- strongswan-5.8.4/src/libstrongswan/threading/mutex.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/threading/mutex.c	2022-07-06 15:47:35.570996000 +0300
@@ -239,7 +239,8 @@
 }
 
 /* use the monotonic clock based version of this function if available */
-#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) && \
+	!defined(HAVE_CONDATTR_CLOCK_MONOTONIC)
 #define pthread_cond_timedwait pthread_cond_timedwait_monotonic
 #endif
 
@@ -336,7 +337,7 @@
 				pthread_condattr_t condattr;
 				pthread_condattr_init(&condattr);
 #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
-				pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
+				pthread_condattr_setclock(&condattr, TIME_CLOCK_ID);
 #endif
 				pthread_cond_init(&this->condvar, &condattr);
 				pthread_condattr_destroy(&condattr);
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/chunk.c strongswancont-5.8.4-svc/src/libstrongswan/utils/chunk.c
--- strongswan-5.8.4/src/libstrongswan/utils/chunk.c	2019-12-17 01:04:51.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/chunk.c	2023-03-24 14:04:58.275622000 +0300
@@ -347,10 +347,30 @@
 	flags |= O_BINARY;
 #endif
 
+#ifdef WIN32
+	int wlen = 0, fn_len_s = strlen(path);
+	if(fn_len_s == 0)
+	{
+		return NULL;
+	}		
+	wchar_t wpath[MAX_PATH];
+	wlen = MultiByteToWideChar(CP_UTF8, 0, path, fn_len_s, wpath, fn_len_s);
+	if(wlen >= MAX_PATH) 
+	{		
+		return NULL;
+	}
+	wpath[wlen] = L'\0';
+	
+	INIT(chunk,
+		.fd = _wopen(wpath, flags),
+		.wr = wr,
+	);
+#else 
 	INIT(chunk,
 		.fd = open(path, flags),
 		.wr = wr,
 	);
+#endif
 
 	if (chunk->fd == -1)
 	{
@@ -790,7 +810,7 @@
 		{
 			if (sane)
 			{
-				sane->ptr[i] = replace;
+				//sane->ptr[i] = replace;
 			}
 			printable = FALSE;
 		}
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/compat/android.h strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/android.h
--- strongswan-5.8.4/src/libstrongswan/utils/compat/android.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/android.h	2022-07-06 15:47:35.602997000 +0300
@@ -37,6 +37,9 @@
 #define HAVE_PTHREAD_CONDATTR_INIT 1
 #define HAVE_CONDATTR_CLOCK_MONOTONIC 1
 
+#undef TIME_CLOCK_ID
+#define TIME_CLOCK_ID CLOCK_REALTIME
+
 #define HAVE_SYS_CAPABILITY_H 1
 
 #else /* __ANDROID_API__ */
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/compat/unix.h strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/unix.h
--- strongswan-5.8.4/src/libstrongswan/utils/compat/unix.h	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/unix.h	2020-11-30 16:52:55.000000000 +0300
@@ -0,0 +1,15 @@
+
+#ifndef _AFUNIX_
+#define _AFUNIX_
+
+#define UNIX_PATH_MAX 108
+
+typedef struct sockaddr_un
+{
+     ADDRESS_FAMILY sun_family;
+     char sun_path[UNIX_PATH_MAX];
+} SOCKADDR_UN, *PSOCKADDR_UN;
+
+#define SIO_AF_UNIX_GETPEERPID _WSAIOR(IOC_VENDOR, 256)
+
+#endif /* _AFUNIX_ */
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/compat/windows.c strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/windows.c
--- strongswan-5.8.4/src/libstrongswan/utils/compat/windows.c	2016-04-22 23:01:35.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/windows.c	2022-12-05 16:24:40.188691000 +0300
@@ -16,9 +16,43 @@
 /* WSAPoll() */
 #define _WIN32_WINNT 0x0600
 
-#include <utils/utils.h>
+#include "windows.h"
+
+/**
+ * MT safe dlerror variant with caller supplied buffer
+ * See header
+ */
+char *dlerror_mt(char *buf, size_t buf_len)
+{
+	return human_readable_error(buf, GetLastError(), buf_len);
+}
+
+/**
+ * 
+ * MT safe variant that only performs GetLastError() for the supplied
+ * variable in the system error message catalogue
+ * See header.
+ */
+char *human_readable_error(char *buf, DWORD err, size_t buf_len)
+{
+	char *pos;
+
+	if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+					  NULL, err, 0, buf, buf_len, NULL) > 0)
+	{
+		pos = strchr(buf, '\n');
+		if (pos)
+		{
+			*pos = '\0';
+		}
+	}
+	else
+	{
+		snprintf(buf, buf_len, "(%u)", err);
+	}	
+	return buf;
+}
 
-#include <errno.h>
 
 /**
  * See header
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/compat/windows.h strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/windows.h
--- strongswan-5.8.4/src/libstrongswan/utils/compat/windows.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/compat/windows.h	2022-07-08 13:24:01.735332000 +0300
@@ -21,12 +21,21 @@
 #ifndef WINDOWS_H_
 #define WINDOWS_H_
 
+#include <errno.h>
+
+/* Defined in order to be able to build the openssl plugin */
+#define NOCRYPT
+
 #include <winsock2.h>
+#include <devpropdef.h>
 #include <ws2tcpip.h>
 #include <direct.h>
 #include <inttypes.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <setupapi.h>
+
+#include "unix.h"
 
 /* undef Windows variants evaluating values more than once */
 #undef min
@@ -39,6 +48,8 @@
 /* used by Windows API, but we have our own */
 #undef CALLBACK
 
+#include <utils/utils.h>
+
 /* UID/GID types for capabilities, even if not supported */
 typedef u_int uid_t;
 typedef u_int gid_t;
@@ -137,12 +148,12 @@
 /**
  * Provided by printf hook backend
  */
-int asprintf(char **strp, const char *fmt, ...);
+//int asprintf(char **strp, const char *fmt, ...);
 
 /**
  * Provided by printf hook backend
  */
-int vasprintf(char **strp, const char *fmt, va_list ap);
+//int vasprintf(char **strp, const char *fmt, va_list ap);
 
 /**
  * timeradd(3) from <sys/time.h>
@@ -263,6 +274,24 @@
 char* dlerror(void);
 
 /**
+ * thread save dlerror variant, uses caller supplied buffer
+ * @param  buf     caller supplied buffer
+ * @param  buf_len length of caller supplied buffer
+ * @return             caller supplied buffer
+ */
+char *dlerror_mt(char *buf, size_t buf_len);
+
+/**
+ * function for translating the given error into a human readable error message
+ * using FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, ...)
+ * @param  buf caller supplied buffer
+ * @param  err caller supplied erorr value to translate
+ * @param  buf_len length of caller supplied buffer
+ * @return             caller supplied buffer
+ */
+char *human_readable_error(char *buf, DWORD err, size_t buf_len);
+
+/**
  * dlclose() from <dlfcn.h>
  */
 int dlclose(void *handle);
@@ -278,6 +307,26 @@
 char* getpass(const char *prompt);
 #define HAVE_GETPASS
 
+WINSETUPAPI BOOL WINAPI SetupDiGetDeviceInterfacePropertyW(
+    HDEVINFO                  DeviceInfoSet,
+    PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
+    const DEVPROPKEY          *PropertyKey,
+    DEVPROPTYPE               *PropertyType,
+    PBYTE                     PropertyBuffer,
+    DWORD                     PropertyBufferSize,
+    PDWORD                    RequiredSize,
+    DWORD                     Flags
+);
+
+WINAPI LSTATUS RegSetKeyValueA(
+    HKEY    hKey,
+    LPCSTR  lpSubKey,
+    LPCSTR  lpValueName,
+    DWORD   dwType,
+    LPCVOID lpData,
+    DWORD   cbData
+) __attribute__((dllimport));
+
 /**
  * Map MSG_DONTWAIT to the reserved, but deprecated MSG_INTERRUPT
  */
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/debug.c strongswancont-5.8.4-svc/src/libstrongswan/utils/debug.c
--- strongswan-5.8.4/src/libstrongswan/utils/debug.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/debug.c	2022-07-06 15:47:35.630997000 +0300
@@ -17,7 +17,7 @@
 
 #include "debug.h"
 
-ENUM(debug_names, DBG_DMN, DBG_ANY,
+ENUM(debug_names, DBG_DMN, DBG_CNT,
 	"DMN",
 	"MGR",
 	"IKE",
@@ -36,10 +36,11 @@
 	"APP",
 	"ESP",
 	"LIB",
-	"ANY",
+	"CNT",	
+	//"ANY",	
 );
 
-ENUM(debug_lower_names, DBG_DMN, DBG_ANY,
+ENUM(debug_lower_names, DBG_DMN, DBG_CNT,
 	"dmn",
 	"mgr",
 	"ike",
@@ -58,7 +59,8 @@
 	"app",
 	"esp",
 	"lib",
-	"any",
+	"cnt",
+	//"any",
 );
 
 /**
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/debug.h strongswancont-5.8.4-svc/src/libstrongswan/utils/debug.h
--- strongswan-5.8.4/src/libstrongswan/utils/debug.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/debug.h	2022-07-06 15:47:35.606997000 +0300
@@ -68,6 +68,8 @@
 	DBG_ESP,
 	/** libstrongswan */
 	DBG_LIB,
+	/** contact plugins */
+	DBG_CNT,	
 	/** number of groups */
 	DBG_MAX,
 	/** pseudo group with all groups */
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/identification.c strongswancont-5.8.4-svc/src/libstrongswan/utils/identification.c
--- strongswan-5.8.4/src/libstrongswan/utils/identification.c	2019-08-29 12:55:35.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/identification.c	2023-05-07 14:24:37.762207000 +0300
@@ -66,26 +66,28 @@
 	{"ND", 					OID_NAME_DISTINGUISHER,		ASN1_PRINTABLESTRING},
 	{"UID", 				OID_PILOT_USERID,			ASN1_PRINTABLESTRING},
 	{"DC", 					OID_PILOT_DOMAIN_COMPONENT, ASN1_PRINTABLESTRING},
-	{"CN",					OID_COMMON_NAME,			ASN1_PRINTABLESTRING},
-	{"S", 					OID_SURNAME,				ASN1_PRINTABLESTRING},
+	{"CN",					OID_COMMON_NAME,			ASN1_UTF8STRING},
+	{"S", 					OID_SURNAME,				ASN1_UTF8STRING},
 	{"SN", 					OID_SERIAL_NUMBER,			ASN1_PRINTABLESTRING},
 	{"serialNumber", 		OID_SERIAL_NUMBER,			ASN1_PRINTABLESTRING},
 	{"C", 					OID_COUNTRY,				ASN1_PRINTABLESTRING},
-	{"L", 					OID_LOCALITY,				ASN1_PRINTABLESTRING},
-	{"ST",					OID_STATE_OR_PROVINCE,		ASN1_PRINTABLESTRING},
-	{"STREET",				OID_STREET_ADDRESS,			ASN1_PRINTABLESTRING},
-	{"O", 					OID_ORGANIZATION,			ASN1_PRINTABLESTRING},
-	{"OU", 					OID_ORGANIZATION_UNIT,		ASN1_PRINTABLESTRING},
-	{"T", 					OID_TITLE,					ASN1_PRINTABLESTRING},
-	{"D", 					OID_DESCRIPTION,			ASN1_PRINTABLESTRING},
+	{"L", 					OID_LOCALITY,				ASN1_UTF8STRING},
+	{"ST",					OID_STATE_OR_PROVINCE,		ASN1_UTF8STRING},
+	{"STREET",				OID_STREET_ADDRESS,			ASN1_UTF8STRING},
+	{"O", 					OID_ORGANIZATION,			ASN1_UTF8STRING},
+	{"OU", 					OID_ORGANIZATION_UNIT,		ASN1_UTF8STRING},
+	{"T", 					OID_TITLE,					ASN1_UTF8STRING},
+	{"D", 					OID_DESCRIPTION,			ASN1_UTF8STRING},
 	{"postalAddress",		OID_POSTAL_ADDRESS,			ASN1_PRINTABLESTRING},
 	{"postalCode",			OID_POSTAL_CODE,			ASN1_PRINTABLESTRING},
-	{"N", 					OID_NAME,					ASN1_PRINTABLESTRING},
-	{"G", 					OID_GIVEN_NAME,				ASN1_PRINTABLESTRING},
+	{"N", 					OID_NAME,					ASN1_UTF8STRING},
+	{"G", 					OID_GIVEN_NAME,				ASN1_UTF8STRING},
 	{"I", 					OID_INITIALS,				ASN1_PRINTABLESTRING},
 	{"dnQualifier", 		OID_DN_QUALIFIER,			ASN1_PRINTABLESTRING},
 	{"dmdName", 			OID_DMD_NAME,				ASN1_PRINTABLESTRING},
-	{"pseudonym", 			OID_PSEUDONYM,				ASN1_PRINTABLESTRING},
+	{"IdentityCard", 		OID_IDENTITY_CARD,			ASN1_PRINTABLESTRING},
+	{"Nick", 				OID_NICK,					ASN1_UTF8STRING},
+	{"pseudonym", 			OID_PSEUDONYM,				ASN1_UTF8STRING},
 	{"ID", 					OID_UNIQUE_IDENTIFIER,		ASN1_PRINTABLESTRING},
 	{"EN", 					OID_EMPLOYEE_NUMBER,		ASN1_PRINTABLESTRING},
 	{"employeeNumber",		OID_EMPLOYEE_NUMBER,		ASN1_PRINTABLESTRING},
@@ -96,7 +98,8 @@
 	{"unstructuredName",	OID_UNSTRUCTURED_NAME,		ASN1_IA5STRING},
 	{"UA",					OID_UNSTRUCTURED_ADDRESS,	ASN1_PRINTABLESTRING},
 	{"unstructuredAddress", OID_UNSTRUCTURED_ADDRESS,	ASN1_PRINTABLESTRING},
-	{"TCGID", 				OID_TCGID,					ASN1_PRINTABLESTRING}
+	{"TCGID", 				OID_TCGID,					ASN1_PRINTABLESTRING},
+	{"organizationId", 		OID_ORGANIZATION_ID,		ASN1_UTF8STRING}
 };
 
 /**
@@ -222,10 +225,12 @@
 		{OID_COUNTRY,			ID_PART_RDN_C},
 		{OID_LOCALITY,			ID_PART_RDN_L},
 		{OID_STATE_OR_PROVINCE,	ID_PART_RDN_ST},
+		{OID_STREET_ADDRESS, 	ID_PART_RDN_STR},
 		{OID_ORGANIZATION,		ID_PART_RDN_O},
 		{OID_ORGANIZATION_UNIT,	ID_PART_RDN_OU},
 		{OID_TITLE,				ID_PART_RDN_T},
 		{OID_DESCRIPTION,		ID_PART_RDN_D},
+		{OID_POSTAL_CODE,		ID_PART_RDN_PC},
 		{OID_NAME,				ID_PART_RDN_N},
 		{OID_GIVEN_NAME,		ID_PART_RDN_G},
 		{OID_INITIALS,			ID_PART_RDN_I},
@@ -235,6 +240,8 @@
 		{OID_UNIQUE_IDENTIFIER,	ID_PART_RDN_ID},
 		{OID_EMAIL_ADDRESS,		ID_PART_RDN_E},
 		{OID_EMPLOYEE_NUMBER,	ID_PART_RDN_EN},
+		{OID_IDENTITY_CARD,		ID_PART_RDN_IC},
+		{OID_NICK,				ID_PART_RDN_NICK},
 	};
 
 	VA_ARGS_VGET(args, type, data);
@@ -1353,6 +1360,7 @@
 			break;
 		case ID_FQDN:
 		case ID_RFC822_ADDR:
+		case ID_DER_ASN1_GN_URI:
 			this->public.hash = _hash_binary;
 			this->public.equals = _equals_strcasecmp;
 			this->public.matches = _matches_string;
@@ -1416,6 +1424,7 @@
 		{ "asn1gn:",		ID_DER_ASN1_GN			},
 		{ "xmppaddr:",		ID_DER_ASN1_GN          },
 		{ "keyid:",			ID_KEY_ID				},
+		{ "uri:",			ID_DER_ASN1_GN_URI		},
 	};
 	private_identification_t *this;
 	int i;
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/identification.h strongswancont-5.8.4-svc/src/libstrongswan/utils/identification.h
--- strongswan-5.8.4/src/libstrongswan/utils/identification.h	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/identification.h	2022-07-06 15:47:35.630997000 +0300
@@ -190,6 +190,14 @@
 	ID_PART_RDN_ST,
 	/** Title RDN of a DN */
 	ID_PART_RDN_T,
+	/** Addres in state */
+	ID_PART_RDN_STR,
+	/** Postal code */
+	ID_PART_RDN_PC,
+	/** Identitu Card */
+	ID_PART_RDN_IC,
+	/** Nick */
+	ID_PART_RDN_NICK,
 };
 
 /**
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/utils/object.h strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/object.h
--- strongswan-5.8.4/src/libstrongswan/utils/utils/object.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/object.h	2022-07-06 15:47:35.606997000 +0300
@@ -123,4 +123,15 @@
 	static typeof(_cb_##name) *name = (typeof(_cb_##name)*)_cb_##name; \
 	static ret _cb_##name(param1, ##__VA_ARGS__)
 
+/**
+ * Same as CALLBACK(), but for two void* arguments (e.g. for comparisons).
+ */
+#define CALLBACK2(name, ret, param1, param2, ...) \
+   static ret _cb_##name(union {void *_generic; param1;} \
+   __attribute__((transparent_union)), \
+   union {void *_generic; param2;} \
+   __attribute__((transparent_union)), ##__VA_ARGS__); \
+   static typeof(_cb_##name) *name = (typeof(_cb_##name)*)_cb_##name; \
+   static ret _cb_##name(param1, param2, ##__VA_ARGS__)
+
 #endif /** OBJECT_H_ @} */
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/utils/string.c strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/string.c
--- strongswan-5.8.4/src/libstrongswan/utils/utils/string.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/string.c	2022-07-08 11:57:41.645254000 +0300
@@ -15,6 +15,7 @@
  */
 
 #include <utils/utils.h>
+#include <utils/utils/memory.h>
 
 /**
  * Described in header.
@@ -89,3 +90,31 @@
 	strcpy(dst, pos);
 	return res;
 }
+
+linked_list_t *strsplit(const char *str, const char *tokstr)
+{
+	linked_list_t *list = linked_list_create();
+	size_t str_len = strlen(str);
+	char *saveptr, *tok = NULL, *copy = alloca(str_len+1), *tok_cpy;
+	memcpy(copy, str, str_len);
+	tok = strtok_r(copy, tokstr, &saveptr);
+	if (tok) {
+	    	tok_cpy = malloc(strlen(tok)+1);
+		memcpy(tok_cpy, tok, strlen(tok)+1);
+		list->insert_last(list, tok_cpy);
+		while (TRUE)
+		{
+			tok = strtok_r(NULL, tokstr, &saveptr);
+			if (tok)
+			{
+				size_t substring_length = strlen(tok);
+				char *substring_copy = malloc(substring_length+1);
+				memcpy(substring_copy, tok,  substring_length+1);
+				list->insert_last(list, substring_copy);
+			} else {
+				break;
+			}
+		}
+	} 
+	return list;
+}
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/utils/string.h strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/string.h
--- strongswan-5.8.4/src/libstrongswan/utils/utils/string.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/string.h	2022-07-08 11:58:55.978930000 +0300
@@ -22,6 +22,8 @@
 #ifndef STRING_H_
 #define STRING_H_
 
+#include "../../collections/linked_list.h"
+
 /**
  * Helper function that compares two strings for equality
  */
@@ -100,4 +102,14 @@
  */
 char *strreplace(const char *str, const char *search, const char *replace);
 
+/**
+ * Splits the string into tokens seperated by the given substring
+ * Returns a linked list containing the strings, allocated on the heap.
+ * 
+ * @param str           original string
+ * @param tokstr        String to split the original string with
+ * @return              linked list containing the strings
+ */
+linked_list_t *strsplit(const char *str, const char *tokstr);
+
 #endif /** STRING_H_ @} */
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/utils/time.c strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/time.c
--- strongswan-5.8.4/src/libstrongswan/utils/utils/time.c	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/time.c	2022-07-06 15:47:35.602997000 +0300
@@ -52,7 +52,7 @@
 	 * monotonic time source only if it is also supported by pthread. */
 	timespec_t ts;
 
-	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+	if (clock_gettime(TIME_CLOCK_ID, &ts) == 0)
 	{
 		if (tv)
 		{
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/utils/time.h strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/time.h
--- strongswan-5.8.4/src/libstrongswan/utils/utils/time.h	2018-10-04 00:35:17.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/utils/time.h	2022-07-06 15:47:35.630997000 +0300
@@ -33,6 +33,20 @@
 #define TIME_32_BIT_SIGNED_MAX	0x7fffffff
 
 /**
+ * The clock that should be used for time_monotonic() and conditional variables
+ */
+#ifdef HAVE_CLOCK_GETTIME
+#ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
+/* only can use different clocks if we can set it via attribute */
+#ifndef TIME_CLOCK_ID
+#define TIME_CLOCK_ID CLOCK_MONOTONIC
+#endif
+#else
+#define TIME_CLOCK_ID CLOCK_MONOTONIC
+#endif
+#endif
+
+/**
  * Handle struct timeval like an own type.
  */
 typedef struct timeval timeval_t;
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/windows_helper.c strongswancont-5.8.4-svc/src/libstrongswan/utils/windows_helper.c
--- strongswan-5.8.4/src/libstrongswan/utils/windows_helper.c	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/windows_helper.c	2022-12-08 11:18:00.148410000 +0300
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2020 Noel Kuntze
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "windows_helper.h"
+
+/**
+ * See header
+ */
+bool guid2string(char *dst, size_t dst_len, const GUID *guid, bool braces)
+{
+	size_t ret = 0;
+	char *with_braces = "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+		*without_braces = "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
+	if (braces)
+	{
+		if (dst_len >= 39 )
+		{
+		ret = snprintf(dst, dst_len,
+			with_braces,
+			guid->Data1, guid->Data2, guid->Data3,	
+			guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+			guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);			
+		}
+		else
+		{
+			DBG0(DBG_LIB, "Buffer too small!");
+		}
+	}
+	else
+	{
+		if (dst_len >= 37)
+		{
+		ret = snprintf(dst, dst_len,
+			without_braces,
+			guid->Data1, guid->Data2, guid->Data3,	
+			guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+			guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+		}
+		else {
+			DBG0(DBG_LIB, "Buffer too small!");
+		}
+	}
+	return ret >= 36 ? TRUE : FALSE;
+}
+
+bool guidfromstring(GUID *guid, const char *str, bool with_braces)
+{
+	char *format = with_braces ?
+				   "{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}%n" :
+				   "%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%n";
+	size_t nchars = 0;
+	size_t nfields = sscanf_s(str, format,
+		&guid->Data1, &guid->Data2, &guid->Data3,	
+		&guid->Data4[0], &guid->Data4[1], &guid->Data4[2], &guid->Data4[3],
+		&guid->Data4[4], &guid->Data4[5], &guid->Data4[6], &guid->Data4[7], &nchars);
+	if (nfields == 11 && ((with_braces && nchars == 38) || (!with_braces && nchars == 36)))
+	{
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/**
+ * see header
+ */
+bool registry_wait_get_value(HKEY key, void *caller_buf, DWORD *caller_buf_len,
+							 char *reg_val_name, DWORD *reg_val_type, size_t timeout)
+{
+	/* timeout is in ms */
+	timeval_t now, deadline;
+	DWORD own_ret = FALSE, function_ret_query, function_ret_wait;
+	char buf[512];
+
+	HANDLE handle = CreateEventA(NULL, FALSE, FALSE, NULL);
+	if (!handle)
+	{
+		char buf[512];
+		dlerror_mt(buf, sizeof(buf));
+		DBG1(DBG_LIB, "Failed to create handle: %s", buf);
+		return FALSE;
+	}
+	/* Get current time, add timeout */
+	time_monotonic(&deadline);
+	timeval_add_ms(&deadline, timeout);
+
+	while(TRUE)
+	{
+		/* Try to get value */
+		function_ret_query = RegQueryValueExA(key, reg_val_name, NULL, reg_val_type, caller_buf, (LPDWORD) caller_buf_len);
+		time_monotonic(&now);
+		int64_t ms_to_deadline = (deadline.tv_sec - now.tv_sec) * 1000 + (deadline.tv_usec - now.tv_usec);
+		switch(function_ret_query)
+		{
+			case ERROR_FILE_NOT_FOUND:
+			case ERROR_PATH_NOT_FOUND:
+				/* All vars in this calculation are signed, so no issues
+				 * until the first part overflows (certainly farther in the future than this code will run)
+				 */				
+				if (ms_to_deadline <= 0)
+				{
+					DBG1(DBG_LIB, "Timed out waiting for registry value %s", reg_val_name);
+					goto out;
+					break;
+				}
+				/* Set up handle for notify */
+				if (RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, handle, true) != ERROR_SUCCESS)
+				{
+					dlerror_mt(buf, sizeof(buf));
+					DBG1(DBG_LIB, "Failed to call RegNotifyChangeKeyValue: %s", buf);
+					goto out;
+					break;
+				}
+				function_ret_wait = WaitForSingleObjectEx(handle, ms_to_deadline, FALSE);
+				if(function_ret_wait && function_ret_wait != WAIT_OBJECT_0 )
+				{
+					dlerror_mt(buf, sizeof(buf));
+					DBG1(DBG_LIB, "Failed to wait for event (WaitForSingleObjectEx(): %ld): %s", function_ret_wait, buf);
+					goto out;
+					break;
+				}
+				break;
+			case ERROR_MORE_DATA:
+				caller_buf = realloc(caller_buf, *caller_buf_len);
+				break;
+			case ERROR_SUCCESS:
+			case TRUE:
+				/* succeeded */
+				own_ret = TRUE;
+				goto out;
+				break;
+			case ERROR_INVALID_HANDLE:
+				DBG1(DBG_LIB, "Invalid handle. Failed to read string.");
+				goto out;
+				break;
+			default:
+				dlerror_mt(buf, sizeof(buf));
+				DBG1(DBG_LIB, "Failed to read registry value (RegQueryValueExA): %s", buf);
+				goto out;
+				break;
+		}
+	}
+	out:
+	CloseHandle(handle);
+	return own_ret;
+}
+
+/**
+ * Described in header.
+ */
+char *windows_expand_string(char *buf, DWORD *buf_len, size_t *new_buf_len)
+{
+	size_t new_length = *buf_len, required_size;
+	char *intermediate_buf = NULL;
+
+	for(size_t i=0;i<=2;i++)
+	{
+		intermediate_buf = realloc(intermediate_buf, new_length);
+		required_size = ExpandEnvironmentStringsA(buf, intermediate_buf, new_length);
+		if (required_size > new_length)
+		{
+			new_length = required_size;
+		}
+		else
+		{
+			break;
+		}
+	}
+	*new_buf_len = new_length;
+	return intermediate_buf;
+}
+
+/**
+ * Described in header.
+ */
+HKEY registry_open_wait(HKEY key, char *path, DWORD access, size_t timeout)
+{
+	/* timeout is in ms */
+	HKEY intermediate = NULL;
+	size_t path_len = strlen(path) + 1, ret;
+	char buf[512], *str = path, *tok, *current_path = alloca(path_len),
+		*current_path_cpy = alloca(path_len), *last_part;
+	bool first = TRUE;
+	timeval_t now, deadline;
+	DWORD function_ret_wait;
+	/* Number of iterations */
+
+	// linked_list_t *tokens = strsplit_race(path, "\\");
+	linked_list_t *tokens = strsplit(path, "\\,");
+	tokens->get_last(tokens, (void **) &last_part);
+	enumerator_t *enumerator = tokens->create_enumerator(tokens);
+	
+	HANDLE handle = CreateEventA(NULL, FALSE, FALSE, NULL);
+	if (!handle)
+	{
+		char buf[512];
+		dlerror_mt(buf, sizeof(buf));
+		DBG1(DBG_LIB, "Failed to create handle: %s", buf);
+		return FALSE;
+	}
+
+	/* Get current time, add timeout */
+	time_monotonic(&deadline);
+	timeval_add_ms(&deadline, timeout);	
+	
+	/* In the loop, we check if each key occuring in the path is accessible.
+	 * If a key is not, it will be created by the installation routine
+	 * that was called before this function.
+	 * This means that we instead wait for an event in the registry in
+	 * which the key was created.
+	 */
+	while (enumerator->enumerate(enumerator, &tok))
+	{
+		if (tok)
+		{
+			if (first)
+			{
+				memcpy(current_path, tok, strlen(tok)+1);
+				first = FALSE;
+			}
+			else
+			{
+				memcpy(current_path_cpy, current_path, path_len);
+				snprintf(current_path, path_len, "%s\\%s", current_path_cpy, tok);			
+			}
+			/* Add the new token to the path*/
+			/* Check if the current path is accessible */
+			if (last_part == tok)
+			{
+				access = KEY_NOTIFY;
+			}
+			
+			switch((ret=RegOpenKeyA(key, current_path, &intermediate)))
+			{
+				case true:
+				case ERROR_SUCCESS:
+					break;
+				case ERROR_FILE_NOT_FOUND:
+				case ERROR_PATH_NOT_FOUND:
+					time_monotonic(&now);
+					/* All vars in this calculation are signed, so no issues
+					 * until the first part overflows (certainly farther in the future than this code will run)
+					 */
+					int64_t ms_to_deadline = (deadline.tv_sec - now.tv_sec) * 1000 + (deadline.tv_usec - now.tv_usec);
+					if (ms_to_deadline <= 0)
+					{
+						DBG1(DBG_LIB, "Timed out waiting for registry value %s", current_path);
+						break;
+						break;
+					}
+					/* Setup notifier */
+					if ((function_ret_wait=RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_NAME, handle, true)))
+					{
+						DBG1(DBG_LIB, "Failed to setup notify handle for REG_NOTIFY_CHANGE_NAME on %s using RegNotifyChangeKeyValue: %s",
+							current_path, human_readable_error(buf, function_ret_wait, sizeof(buf)));
+						goto cleanup;
+					}
+					/* Check if we can access the key */
+					switch((ret = RegOpenKeyExA(key, current_path, 0, access, &intermediate)))
+					{
+						case true:
+						case ERROR_SUCCESS:
+							/* Close the notifier handle again and open a new one, just in case the kernel handles reusing of active handles badly.*/
+							CloseHandle(handle);
+							handle = CreateEventA(NULL, FALSE, FALSE, NULL);							
+							if (!handle)
+							{
+								dlerror_mt(buf, sizeof(buf));
+								DBG1(DBG_LIB, "Failed to create handle: %s", buf);
+							}
+							break;
+						case ERROR_FILE_NOT_FOUND:
+						case ERROR_PATH_NOT_FOUND:
+							time_monotonic(&now);
+							/* All vars in this calculation are signed, so no issues
+							 * until the first part overflows (certainly farther in the future than this code will run)
+							 */
+							int64_t ms_to_deadline = (deadline.tv_sec - now.tv_sec) * 1000 + (deadline.tv_usec - now.tv_usec);
+							if (ms_to_deadline <= 0)
+							{
+								DBG1(DBG_LIB, "Timed out waiting for registry value %s", current_path);
+								goto cleanup;
+							}
+							function_ret_wait = WaitForSingleObjectEx(handle, ms_to_deadline, FALSE);
+							switch(function_ret_wait)
+							{
+								case WAIT_OBJECT_0:
+									break;
+								case WAIT_TIMEOUT:
+									DBG1(DBG_LIB, "Failed to wait for event (WaitForSingleObjectEx() for path %s: %ld): The time limit (timeout) was reached", current_path, function_ret_wait);
+									break;
+								case WAIT_FAILED:
+									DBG1(DBG_LIB, "Failed to wait for event (WaitForSingleObjectEx() for path %s: %ld): %s", function_ret_wait, current_path, dlerror_mt(buf, sizeof(buf)));
+									break;
+							}
+							if(function_ret_wait != WAIT_OBJECT_0)
+							{
+								goto cleanup;
+							}
+							break;
+						default:
+							dlerror_mt(buf, sizeof(buf));
+							DBG1(DBG_LIB, "Failed to open registry value (RegOpenKeyEx): (decimal %u) %s", ret, buf);
+							goto cleanup;
+							break;
+					}
+					break;
+				default:
+					dlerror_mt(buf, sizeof(buf));
+					DBG1(DBG_LIB, "Failed to open registry key %s (RegOpenKeyA): (decimal %u) %s", current_path, ret, buf);
+					goto cleanup;
+					break;
+			}
+		}
+	}
+
+cleanup: ;
+	tokens->reset_enumerator(tokens, enumerator);
+	while(enumerator->enumerate(enumerator, &str))
+	{
+		free(str);
+	}
+	enumerator->destroy(enumerator);
+	tokens->destroy(tokens);
+	CloseHandle(handle);
+	return intermediate;
+}
+
+bool check_reboot(HDEVINFO dev_info_set, SP_DEVINFO_DATA *dev_info_data)
+{
+	SP_DEVINSTALL_PARAMS dev_install_params = {
+		.cbSize = sizeof(SP_DEVINSTALL_PARAMS)
+	};
+	bool ret = SetupDiGetDeviceInstallParamsA(dev_info_set, dev_info_data, &dev_install_params);
+	return dev_install_params.Flags & (DI_NEEDREBOOT | DI_NEEDRESTART) & ret;
+}
+
+/**
+ * If dst_len is 0, the buffer is allocated on the heap using malloc()
+ * @param dst
+ * @param dst_len
+ * @param str
+ * @param str_len
+ * @return 
+ */
+int ascii2utf16(LPWSTR *dst, size_t dst_len, const char *str, const size_t str_len)
+{
+	int ret = dst_len;
+	for(int i=0;i<2;i++)
+	{
+	ret = MultiByteToWideChar(CP_ACP, 0, str, str_len, *dst, ret);
+	if(!ret)
+	{
+		char buf[512];
+		DBG1(DBG_LIB, "Failed to convert string (ascii2utf) with dst %p, dst_len %u, str %p and str_Len %u: %u",
+			dst, dst_len, str, str_len, dlerror_mt(buf, sizeof(buf)));
+		return 0;
+	}
+	*dst = malloc(ret*sizeof(WCHAR));
+	if(!(*dst))
+	{
+		DBG1(DBG_LIB, "Failed to convert string (ascii2utf) with dst %p, dst_len %u, str %p and str_Len %u because the required memory of %u byte could not be allocated.",
+			dst, dst_len, str, str_len, ret);
+		return 0;
+	}
+	}
+	return ret;
+}
+
+/**
+ * See header.
+ */
+bool handle_is_valid(HKEY handle)
+{
+	return (handle != NULL && (long long) handle > 1);
+}
\ В конце файла нет новой строки
diff -ruN strongswan-5.8.4/src/libstrongswan/utils/windows_helper.h strongswancont-5.8.4-svc/src/libstrongswan/utils/windows_helper.h
--- strongswan-5.8.4/src/libstrongswan/utils/windows_helper.h	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libstrongswan/utils/windows_helper.h	2022-12-07 14:35:26.544305000 +0300
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 Noel Kuntze
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#ifndef WINDOWS_HELPER_H_
+#define WINDOWS_HELPER_H_
+#include <utils/utils.h>
+#include <utils/compat/windows.h>
+
+#include <synchapi.h>
+
+#include <library.h>
+#define WINDOWS_UNITIALIZED 3131961357
+
+#define WINDOWS_IS_UNITIALIZED(x) (x == WINDOWS_UNITIALIZED)
+/**
+ * helper function for writing guids into character buffers
+ * Thread safe and safe for calling several times.
+ * Writes the GUID in XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX form
+ * @param		dst 	destination buffer for GUID. Has to be at least 37 characters in length.
+ * @param		dst_len	length of destination buffer
+ * @param		GUID 	GUID to transform into a string
+ * @param		braces	print with curly braces or without curly braces
+ * @return		        Boolean indicating success (buffer long enough) or failure (buffer too short)
+ */
+bool guid2string(char *dst, size_t dst_len, const GUID *guid, bool braces);
+
+/**
+ * helper function for reading GUIDs in string form into a GUID type structure.
+ * Thread safe and safe for calling several times.
+ * @param               guid    allocated GUID type structure, will receive the data from the GUID
+ * @param               str     source string to read into the GUID type structure
+ * @param               bool    Whether the guid is enclosed in {} or not
+ * @return			 Boolean indicating success or failure (string too short or not a valid GUID)
+ */
+bool guidfromstring(GUID *guid, const char *str, bool with_braces);
+
+/**
+ * helper function for getting registry values that may not exist yet
+ * @param	key				registry key to query
+ * @param	caller_buf 		caller supplied buffer for storing the queried value. Must be realloc()-atable
+ *							If the function returns FALSE, the content of caller_buf is undefined.
+ * @param	caller_buf_len	length of caller_buf in bytes.
+ 							Will contain the length of the written data in bytes after the function returns.
+ 							If the function returns FALSE, the content of caller_buf_len is undefined.
+ * @param	reg_val_name	name of the value to query
+ * @param	reg_val_type	Will contain the registry type of the value (MULTI_SZ, EXPAND_SZ, ...)
+ * @param	timeout		time (in ms) to wait for the registry key to appear
+ * @return			TRUE if querying succeeded, FALSE if not
+ */
+bool registry_wait_get_value(HKEY key, void *caller_buf, DWORD *caller_buf_len, char *reg_val_name, DWORD *reg_val_type,
+			size_t timeout);
+
+/**
+ * helper function for waiting until the specified path exists (is accessible)
+ * @param       key           root registry key
+ * @param       path          complete path starting under the root registry key
+ * @param       access        unused
+ * @param       timeout       maximum time to wait for the key to be accessible
+ * @return                    Whether the key is accessible within the timeout or not
+ */
+HKEY registry_open_wait(HKEY key, char *path, DWORD access, size_t timeout);
+
+/**
+ * Helper function for expanding strings containing environmental variables in Windows %var% format.
+ * Warning: This function silently fails to expand the string if realloc() fails.
+ * @param	buf 			source buffer to get the original string from
+ * @param 	buf_len 		length of the buffer in bytes
+ * @param	new_buf_len		variable to store the length of the new buffer in (length is in bytes)
+ * @return                             Heap allocated string containing th expanded string.
+ */
+char *windows_expand_string(char *buf, DWORD *buf_len, size_t *new_buf_len);
+
+/**
+ * Helper function for checking if the specified device requires a reboot to complete installation.
+ * @param       dev_info_set    HDEVINFO type struct containing the device
+ * @param       dev_info_data   pointer to the struct containing the device
+ * @return                      State whether a reboot is required or not.
+ */
+bool check_reboot(HDEVINFO dev_info_set, SP_DEVINFO_DATA *dev_info_data);
+
+/**
+ * Helper function for converting ASCII to UTF-16.
+ * @param dst		    pointer to the destination buffer, does not need to be allocated.
+ * @param dst_len	    length of the destination buffer, if it is preallocated. If it is not allocated, 0 has to be passed.
+ * @param str		    ASCII string to be converted
+ * @param str_len	    Length of the ASCII string, if it is not zero/NULL byte terminated. If it is zero/NULl byte terminated, pass -1.
+ * @return 
+ */
+int ascii2utf16(LPWSTR *dst, size_t dst_len, const char *str, const size_t str_len);
+
+/**
+ * Helper function to check if a handle has an actually valid value
+ * @param handle	Handle to check
+ * @return		Bool indicating whether the handle could possibly be valid
+ */
+bool handle_is_valid(HKEY handle);
+#endif
\ В конце файла нет новой строки
diff -ruN strongswan-5.8.4/src/libtpmtss/Android.mk strongswancont-5.8.4-svc/src/libtpmtss/Android.mk
--- strongswan-5.8.4/src/libtpmtss/Android.mk	1970-01-01 03:00:00.000000000 +0300
+++ strongswancont-5.8.4-svc/src/libtpmtss/Android.mk	2022-07-06 15:47:35.726999000 +0300
@@ -0,0 +1,32 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# copy-n-paste from Makefile.am
+libtpmtss_la_SOURCES := \
+	tpm_tss.h tpm_tss.c \
+	tpm_tss_quote_info.h tpm_tss_quote_info.c \
+	tpm_tss_trousers.h tpm_tss_trousers.c \
+	tpm_tss_tss2.h tpm_tss_tss2_v1.c tpm_tss_tss2_v2.c \
+	tpm_tss_tss2_names.h tpm_tss_tss2_names_v1.c tpm_tss_tss2_names_v2.c
+
+LOCAL_SRC_FILES := $(filter %.c,$(libtpmtss_la_SOURCES))
+
+# build libtpmtss --------------------------------------------------------------
+
+LOCAL_C_INCLUDES += \
+	$(strongswan_PATH)/src/libstrongswan
+
+LOCAL_CFLAGS := $(strongswan_CFLAGS)
+
+LOCAL_MODULE := libtpmtss
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_SHARED_LIBRARIES += libstrongswan
+
+include $(BUILD_SHARED_LIBRARY)
+
diff -ruN strongswan-5.8.4/src/starter/starter.c strongswancont-5.8.4-svc/src/starter/starter.c
--- strongswan-5.8.4/src/starter/starter.c	2020-03-29 11:59:15.000000000 +0300
+++ strongswancont-5.8.4-svc/src/starter/starter.c	2022-07-06 15:47:35.762999000 +0300
@@ -456,7 +456,7 @@
 		exit(LSB_RC_FAILURE);
 	}
 
-	DBG1(DBG_APP, "Starting %sSwan "VERSION" IPsec [starter]...",
+	DBG1(DBG_APP, "Starting %sSwanCont "VERSION" IPsec [starter]...",
 		lib->settings->get_bool(lib->settings,
 			"charon.i_dont_care_about_security_and_use_aggressive_mode_psk",
 				FALSE) ? "weak" : "strong");
@@ -496,14 +496,14 @@
 	}
 	if (stat(DEV_RANDOM, &stb) != 0)
 	{
-		DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
+		DBG1(DBG_APP, "unable to start strongSwanCont IPsec -- no %s!", DEV_RANDOM);
 		cleanup();
 		exit(LSB_RC_FAILURE);
 	}
 
 	if (stat(DEV_URANDOM, &stb)!= 0)
 	{
-		DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
+		DBG1(DBG_APP, "unable to start strongSwanCont IPsec -- no %s!", DEV_URANDOM);
 		cleanup();
 		exit(LSB_RC_FAILURE);
 	}
@@ -511,7 +511,7 @@
 	cfg = confread_load(config_file);
 	if (cfg == NULL || cfg->err > 0)
 	{
-		DBG1(DBG_APP, "unable to start strongSwan -- fatal errors in config");
+		DBG1(DBG_APP, "unable to start strongSwanCont -- fatal errors in config");
 		if (cfg)
 		{
 			confread_free(cfg);
