--- src/charon-cmd/charon-cmd.c.orig	2017-01-25 13:19:32.000000000 +0100
+++ src/charon-cmd/charon-cmd.c	2017-03-31 10:16:02.000000000 +0200
@@ -344,8 +344,8 @@
 	{
 		exit(SS_RC_INITIALIZATION_FAILED);
 	}
-	lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0");
-	lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0");
+	lib->settings->set_int(lib->settings, "charon-cmd.port", CHARON_UDP_PORT);
+	lib->settings->set_int(lib->settings, "charon-cmd.port_nat_t", CHARON_NATT_PORT);
 	if (!charon->initialize(charon,
 			lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS)))
 	{
--- src/charon-cmd/cmd/cmd_connection.c.orig	2016-04-22 22:01:35.000000000 +0200
+++ src/charon-cmd/cmd/cmd_connection.c	2017-09-22 21:47:41.000000000 +0200
@@ -26,7 +26,12 @@
 #include <threading/thread.h>
 #include <daemon.h>
 
+#ifdef TEST_STROKE_STATUS
+#include <stroke_attribute.h>
+#include <stroke_list.h>
+#endif
 typedef enum profile_t profile_t;
+typedef enum modeconfig_t modeconfig_t;
 typedef struct private_cmd_connection_t private_cmd_connection_t;
 
 /**
@@ -39,6 +44,8 @@
 	PROF_V2_PUB_EAP,
 	PROF_V1_PUB,
 	PROF_V1_PUB_AM,
+	PROF_V1_PSK,
+	PROF_V1_PSK_AM,
 	PROF_V1_XAUTH,
 	PROF_V1_XAUTH_AM,
 	PROF_V1_XAUTH_PSK,
@@ -53,6 +60,8 @@
 	"ikev2-pub-eap",
 	"ikev1-pub",
 	"ikev1-pub-am",
+	"ikev1-psk",
+	"ikev1-psk-am",
 	"ikev1-xauth",
 	"ikev1-xauth-am",
 	"ikev1-xauth-psk",
@@ -62,6 +71,21 @@
 );
 
 /**
+ * modeconfig mode
+ */
+enum modeconfig_t {
+	MODE_CONFIG_PULL,
+	MODE_CONFIG_PUSH,
+	MODE_CONFIG_OFF,
+};
+
+ENUM(modeconfig_modes, MODE_CONFIG_PULL, MODE_CONFIG_OFF,
+	"pull",
+	"push",
+	"off",
+);
+
+/**
  * Private data of an cmd_connection_t object.
  */
 struct private_cmd_connection_t {
@@ -125,6 +149,43 @@
 	 * Selected connection profile
 	 */
 	profile_t profile;
+
+	/**
+	 * modeconfig mode
+	 */
+	modeconfig_t modeconfig;
+
+	/**
+	 * Virtual IP address
+	 */
+	host_t *virtual_addr;
+
+	/**
+	 * IPsec mode
+	 */
+	ipsec_mode_t mode;
+
+	/**
+	 * L2TP mode
+	 */
+	bool l2tp;
+
+	/**
+	 * Fragmentation
+	 */
+	fragmentation_t fragmentation;
+
+#ifdef TEST_STROKE_STATUS
+	/**
+	 * attribute provider
+	 */
+	stroke_attribute_t *attribute;
+
+	/**
+	 * status information logging
+	 */
+	stroke_list_t *list;
+#endif
 };
 
 /**
@@ -164,12 +225,14 @@
 			version = IKEV2;
 			break;
 		case PROF_V1_PUB_AM:
+		case PROF_V1_PSK_AM:
 		case PROF_V1_XAUTH_AM:
 		case PROF_V1_XAUTH_PSK_AM:
 		case PROF_V1_HYBRID_AM:
 			peer.aggressive = TRUE;
 			/* FALL */
 		case PROF_V1_PUB:
+		case PROF_V1_PSK:
 		case PROF_V1_XAUTH:
 		case PROF_V1_XAUTH_PSK:
 		case PROF_V1_HYBRID:
@@ -177,13 +240,24 @@
 			break;
 	}
 
+	/* include the virtual IP in traffic selector list if modeconfig is on */
+	if (this->modeconfig != MODE_CONFIG_OFF)
+	{
+		this->local_ts->insert_last(this->local_ts, traffic_selector_create_dynamic(0, 0, 65535));
+	}
+	/* set push mode only (pull is the default and off is only internal) */
+	if (this->modeconfig == MODE_CONFIG_PUSH)
+	{
+		peer.push_mode = TRUE;
+	}
+
 	local_port = charon->socket->get_port(charon->socket, FALSE);
 	if (local_port != IKEV2_UDP_PORT)
 	{
 		remote_port = IKEV2_NATT_PORT;
 	}
 	ike_cfg = ike_cfg_create(version, TRUE, FALSE, "0.0.0.0", local_port,
-					this->host, remote_port, FRAGMENTATION_NO, 0);
+					this->host, remote_port, this->fragmentation, 0);
 	if (this->ike_proposals->get_count(this->ike_proposals))
 	{
 		while (this->ike_proposals->remove_first(this->ike_proposals,
@@ -304,6 +378,11 @@
 			add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
 			add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY);
 			break;
+		case PROF_V1_PSK:
+		case PROF_V1_PSK_AM:
+			add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PSK);
+			add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PSK);
+			break;
 		case PROF_V1_XAUTH:
 		case PROF_V1_XAUTH_AM:
 			add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
@@ -345,7 +424,7 @@
 				.jitter = 300 /* 5min */
 			}
 		},
-		.mode = MODE_TUNNEL,
+		.mode = this->mode,
 	};
 
 	child_cfg = child_cfg_create("cmd", &child);
@@ -360,8 +439,23 @@
 	else
 	{
 		child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
-		child_cfg->add_proposal(child_cfg,
-								proposal_create_default_aead(PROTO_ESP));
+		child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
+	}
+	/* for L2TP add dynamic UDP/L2TP port TS for local and remote */
+	if (this->l2tp)
+	{
+		DBG2(DBG_IKE, "adding dynamic UDP/L2TP ports for L2TP");
+		ts = traffic_selector_create_dynamic(IPPROTO_UDP, 1701, 1701);
+		this->local_ts->insert_first(this->local_ts, ts);
+		ts = traffic_selector_create_dynamic(IPPROTO_UDP, 1701, 1701);
+		this->remote_ts->insert_first(this->remote_ts, ts);
+	}
+	/* add a dynamic TS for local side if none given (i.e. modeconfig is off) */
+	if (this->local_ts->get_count(this->local_ts) == 0)
+	{
+		DBG2(DBG_IKE, "adding local dynamic TS 0/0");
+		ts = traffic_selector_create_dynamic(0, 0, 65535);
+		this->local_ts->insert_last(this->local_ts, ts);
 	}
 	while (this->local_ts->remove_first(this->local_ts, (void**)&ts) == SUCCESS)
 	{
@@ -369,6 +463,7 @@
 	}
 	if (this->remote_ts->get_count(this->remote_ts) == 0)
 	{
+		DBG2(DBG_IKE, "adding remote TS 0.0.0.0/0");
 		/* add a 0.0.0.0/0 TS for remote side if none given */
 		ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
 									"0.0.0.0", 0, "255.255.255.255", 65535);
@@ -391,17 +486,42 @@
 	}
 	if (has_v4)
 	{
-		peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
+		if (this->modeconfig == MODE_CONFIG_OFF)
+		{
+			DBG2(DBG_IKE, "not adding virtual IP 0/0 because modeconfig is off");
+		}
+		else
+		{
+			peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
+		}
 	}
 	if (has_v6)
 	{
-		peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("::", 0));
+		if (this->modeconfig == MODE_CONFIG_OFF)
+		{
+			DBG2(DBG_IKE, "not adding virtual IP 0/0 because modeconfig is off");
+		}
+		else
+		{
+			peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("::", 0));
+		}
 	}
 	peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg));
 
 	return child_cfg;
 }
+#ifdef TEST_STROKE_STATUS
+static stroke_msg_t *create_stroke_msg(int type)
+{
+	stroke_msg_t *msg;
 
+	INIT(msg,
+		.type = type,
+		.length = offsetof(stroke_msg_t, buffer),
+	);
+	return msg;
+}
+#endif
 /**
  * Initiate the configured connection
  */
@@ -410,6 +530,8 @@
 	peer_cfg_t *peer_cfg;
 	child_cfg_t *child_cfg;
 	pid_t pid = this->pid;
+	host_t *dst, *src;
+	char *iface;
 
 	if (!this->host)
 	{
@@ -423,6 +545,39 @@
 		terminate(pid);
 		return JOB_REQUEUE_NONE;
 	}
+	if (this->virtual_addr)
+	{
+		DBG2(DBG_IKE, "creating host object for %s", this->host);
+		dst = host_create_from_string(this->host, 
+					lib->settings->get_int(lib->settings, "charon-cmd.port", CHARON_UDP_PORT));
+		if (!dst)
+		{
+			DBG1(DBG_CFG, "invalid host: %s", this->host);
+			terminate(pid);
+			return JOB_REQUEUE_NONE;
+		}
+		DBG2(DBG_IKE, "getting source address for %H", dst);
+		src = charon->kernel->get_source_addr(charon->kernel, dst, NULL);
+		free(dst);
+		if (!src)
+		{
+			DBG1(DBG_CFG, "unable to get local address");
+			terminate(pid);
+			return JOB_REQUEUE_NONE;
+		}
+		DBG2(DBG_IKE, "getting interface for %H", src);
+		charon->kernel->get_interface(charon->kernel, src, &iface);
+		free(src);
+		if (!iface)
+		{
+			DBG1(DBG_CFG, "unable to find interface for hist %H", src);
+			terminate(pid);
+			return JOB_REQUEUE_NONE;
+		}
+		DBG2(DBG_IKE, "adding virtual IP address %H on %s", this->virtual_addr, iface);
+		charon->kernel->add_ip(charon->kernel, this->virtual_addr, -1, iface);
+		free(iface);
+	}
 
 	peer_cfg = create_peer_cfg(this);
 
@@ -440,6 +595,14 @@
 	{
 		terminate(pid);
 	}
+
+#ifdef TEST_STROKE_STATUS
+    stroke_msg_t *msg = create_stroke_msg(STR_STATUS_ALL);
+
+    static void stroke_status(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out, bool all, bool wait)
+    this->list->status(this->list, msg, stdout, TRUE, TRUE);
+#endif
+
 	return JOB_REQUEUE_NONE;
 }
 
@@ -475,6 +638,38 @@
 	this->profile = profile;
 }
 
+/**
+ * Parse modeconfig modes
+ */
+static void set_modeconfig(private_cmd_connection_t *this, char *mode)
+{
+	modeconfig_t modeconfig;
+
+	if (!enum_from_name(modeconfig_modes, mode, &modeconfig))
+	{
+		DBG1(DBG_CFG, "unknown modeconfig mode: %s", mode);
+		exit(1);
+	}
+	this->modeconfig = modeconfig;
+}
+
+/**
+ * Create a virtual host from string
+ */
+static void add_virtual_ip(private_cmd_connection_t *this, char *ip)
+{
+	host_t *addr;
+
+	addr = host_create_from_string(ip, 
+				lib->settings->get_int(lib->settings, "charon-cmd.port", CHARON_UDP_PORT));
+	if (!addr)
+	{
+		DBG1(DBG_CFG, "invalid virtual IP: %s", ip);
+		exit(1);
+	}
+	this->virtual_addr = addr;
+}
+
 METHOD(cmd_connection_t, handle, bool,
 	private_cmd_connection_t *this, cmd_option_type_t opt, char *arg)
 {
@@ -533,6 +728,29 @@
 		case CMD_OPT_PROFILE:
 			set_profile(this, arg);
 			break;
+		case CMD_OPT_MODE_CONFIG:
+		    DBG2(DBG_CFG, "set modeconfig to %s", arg);
+			set_modeconfig(this, arg);
+			break;
+		case CMD_OPT_VIRTUAL_IP:
+		    DBG2(DBG_CFG, "set virtual IP to %s", arg);
+			add_virtual_ip(this, arg);
+			break;
+		case CMD_OPT_TRANSPORT_MODE:
+		    DBG2(DBG_CFG, "set transport mode");
+			this->mode = MODE_TRANSPORT;
+			break;
+		case CMD_OPT_L2TP:
+			this->l2tp = TRUE;
+		    DBG2(DBG_CFG, "set transport mode for L2TP");
+			this->mode = MODE_TRANSPORT;
+		    DBG2(DBG_CFG, "turn off modeconfig for L2TP");
+			set_modeconfig(this, "off");
+			break;
+		case CMD_OPT_FRAGMENTATION:
+		    DBG2(DBG_CFG, "turn on fragmentation");
+			this->fragmentation = FRAGMENTATION_YES;
+			break;
 		default:
 			return FALSE;
 	}
@@ -550,6 +768,14 @@
 								offsetof(traffic_selector_t, destroy));
 	this->remote_ts->destroy_offset(this->remote_ts,
 								offsetof(traffic_selector_t, destroy));
+#ifdef TEST_STROKE_STATUS
+	this->list->destroy(this->list);
+#endif
+	if (this->virtual_addr)
+	{
+		DBG2(DBG_IKE, "removing virtual IP address %H", this->virtual_addr);
+		charon->kernel->del_ip(charon->kernel, this->virtual_addr, -1, TRUE);
+	}
 	free(this);
 }
 
@@ -571,12 +797,16 @@
 		.ike_proposals = linked_list_create(),
 		.child_proposals = linked_list_create(),
 		.profile = PROF_UNDEF,
+		.modeconfig = MODE_CONFIG_PULL,
+		.mode = MODE_TUNNEL,
+		.l2tp = FALSE,
+		.fragmentation = FRAGMENTATION_NO,
+#ifdef TEST_STROKE_STATUS
+        .attribute = stroke_attribute_create(),
+        .list = stroke_list_create(this->attribute),
+#endif
 	);
 
-	/* always include the virtual IP in traffic selector list */
-	this->local_ts->insert_last(this->local_ts,
-								traffic_selector_create_dynamic(0, 0, 65535));
-
 	/* queue job, gets initiated as soon as we are up and running */
 	lib->processor->queue_job(lib->processor,
 		(job_t*)callback_job_create_with_prio(
--- src/charon-cmd/cmd/cmd_creds.c.orig	2016-04-22 22:01:35.000000000 +0200
+++ src/charon-cmd/cmd/cmd_creds.c	2017-06-21 11:54:42.000000000 +0200
@@ -19,12 +19,17 @@
 #include "cmd_creds.h"
 
 #include <unistd.h>
+#include <ctype.h>
 
 #include <utils/debug.h>
 #include <credentials/sets/mem_cred.h>
 #include <credentials/containers/pkcs12.h>
 #include <credentials/sets/callback_cred.h>
 
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+
 typedef struct private_cmd_creds_t private_cmd_creds_t;
 
 /**
@@ -58,11 +63,45 @@
 	char *agent;
 
 	/**
+	 * Path to local public key
+	 */
+	char *local_pk;
+
+	/**
+	 * Path to remote public key
+	 */
+	char *remote_pk;
+
+	/**
 	 * Local identity
 	 */
 	char *identity;
+
+	/**
+	 * Remote identity
+	 */
+	char *remote_identity;
 };
 
+void
+print_trace (void)
+{
+  void *array[10];
+  size_t size;
+  char **strings;
+  size_t i;
+
+  size = backtrace (array, 10);
+  strings = backtrace_symbols (array, size);
+
+  printf ("Obtained %zd stack frames.\n", size);
+
+  for (i = 0; i < size; i++)
+     printf ("%s\n", strings[i]);
+
+  free (strings);
+}
+
 /**
  * Callback function to prompt for secret
  */
@@ -73,10 +112,15 @@
 {
 	shared_key_t *shared;
 	char *label, *pwd = NULL;
+	char buf[512] ;
+	size_t l ;
+
+    //print_trace () ;
 
 	if (type == this->prompted)
 	{
-		return NULL;
+		DBG2(DBG_CFG, "prompting for the same type ('%N') again", shared_key_type_names, type);
+        // return NULL;
 	}
 	switch (type)
 	{
@@ -95,9 +139,18 @@
 		default:
 			return NULL;
 	}
-#ifdef HAVE_GETPASS
-	pwd = getpass(label);
-#endif
+
+	fflush (stdout) ;
+	puts (label) ;
+	fflush (stdout) ;
+	memset (buf, 0, sizeof (buf)) ;
+	fgets(buf, sizeof(buf)-1, stdin) ;
+	l = strlen (buf) ;
+	while (l > 0 && isspace (buf[l-1]))
+		l-- ;
+	buf[l] = '\0' ;
+	pwd = buf;
+
 	if (!pwd || strlen(pwd) == 0)
 	{
 		return NULL;
@@ -117,6 +170,134 @@
 	return shared->get_ref(shared);
 }
 
+/** Length of smartcard specifier parts (module, keyid) */
+#define SC_PART_LEN 128
+
+/**
+ * Kind of smartcard specifier token
+ */
+typedef enum {
+	SC_FORMAT_SLOT_MODULE_KEYID,
+	SC_FORMAT_SLOT_KEYID,
+	SC_FORMAT_KEYID,
+	SC_FORMAT_INVALID,
+} smartcard_format_t;
+
+/**
+ * Parse a smartcard specifier token
+ */
+static smartcard_format_t parse_smartcard(char *smartcard, u_int *slot,
+										  char *module, char *keyid)
+{
+	/* The token has one of the following three formats:
+	 * - %smartcard<slot>@<module>:<keyid>
+	 * - %smartcard<slot>:<keyid>
+	 * - %smartcard:<keyid>
+	 */
+	char buf[2 * SC_PART_LEN], *pos;
+
+	if (sscanf(smartcard, "%%smartcard%u@%255s", slot, buf) == 2)
+	{
+		pos = strchr(buf, ':');
+		if (!pos)
+		{
+			return SC_FORMAT_INVALID;
+		}
+		*pos++ = '\0';
+		snprintf(module, SC_PART_LEN, "%s", buf);
+		snprintf(keyid, SC_PART_LEN, "%s", pos);
+		return SC_FORMAT_SLOT_MODULE_KEYID;
+	}
+	if (sscanf(smartcard, "%%smartcard%u:%127s", slot, keyid) == 2)
+	{
+		return SC_FORMAT_SLOT_KEYID;
+	}
+	if (sscanf(smartcard, "%%smartcard:%127s", keyid) == 1)
+	{
+		return SC_FORMAT_KEYID;
+	}
+	return SC_FORMAT_INVALID;
+}
+
+/**
+ * Load a credential from a smartcard
+ */
+static certificate_t *load_from_smartcard(smartcard_format_t format,
+										  u_int slot, char *module, char *keyid,
+										  credential_type_t type, int subtype)
+{
+	chunk_t chunk;
+	void *cred;
+
+	chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
+	switch (format)
+	{
+		case SC_FORMAT_SLOT_MODULE_KEYID:
+			cred = lib->creds->create(lib->creds, type, subtype,
+						BUILD_PKCS11_SLOT, slot,
+						BUILD_PKCS11_MODULE, module,
+						BUILD_PKCS11_KEYID, chunk, BUILD_END);
+			break;
+		case SC_FORMAT_SLOT_KEYID:
+			cred = lib->creds->create(lib->creds, type, subtype,
+						BUILD_PKCS11_SLOT, slot,
+						BUILD_PKCS11_KEYID, chunk, BUILD_END);
+			break;
+		case SC_FORMAT_KEYID:
+			cred = lib->creds->create(lib->creds, type, subtype,
+						BUILD_PKCS11_KEYID, chunk, BUILD_END);
+			break;
+		default:
+			cred = NULL;
+			break;
+	}
+	free(chunk.ptr);
+
+	return cred;
+}
+
+/**
+ * Load a credential from a smartcard with id
+ */
+static certificate_t *load_from_smartcard_with_id(
+							smartcard_format_t format,
+							u_int slot, char *module, char *keyid,
+							credential_type_t type, int subtype,
+							identification_t *id)
+{
+	chunk_t chunk;
+	void *cred;
+
+	chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
+	switch (format)
+	{
+		case SC_FORMAT_SLOT_MODULE_KEYID:
+			cred = lib->creds->create(lib->creds, type, subtype,
+						BUILD_PKCS11_SLOT, slot,
+						BUILD_PKCS11_MODULE, module,
+						BUILD_PKCS11_KEYID, chunk, 
+						BUILD_SUBJECT, id, BUILD_END);
+			break;
+		case SC_FORMAT_SLOT_KEYID:
+			cred = lib->creds->create(lib->creds, type, subtype,
+						BUILD_PKCS11_SLOT, slot,
+						BUILD_PKCS11_KEYID, chunk, 
+						BUILD_SUBJECT, id, BUILD_END);
+			break;
+		case SC_FORMAT_KEYID:
+			cred = lib->creds->create(lib->creds, type, subtype,
+						BUILD_PKCS11_KEYID, chunk, 
+						BUILD_SUBJECT, id, BUILD_END);
+			break;
+		default:
+			cred = NULL;
+			break;
+	}
+	free(chunk.ptr);
+
+	return cred;
+}
+
 /**
  * Load a trusted certificate from path
  */
@@ -124,31 +305,153 @@
 {
 	certificate_t *cert;
 
-	cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+	DBG2(DBG_CFG, "  load_cert(%s)", path);
+	if (strpfx(path, "%smartcard"))
+	{
+		smartcard_format_t format;
+		char module[SC_PART_LEN], keyid[SC_PART_LEN];
+		u_int slot;
+
+		format = parse_smartcard(path, &slot, module, keyid);
+		if (format != SC_FORMAT_INVALID)
+		{
+			cert = (certificate_t*)load_from_smartcard(format,
+					slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
+		}
+	}
+	else
+	{
+		cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
 							  BUILD_FROM_FILE, path, BUILD_END);
+	}
 	if (!cert)
 	{
 		DBG1(DBG_CFG, "loading certificate from '%s' failed", path);
 		exit(1);
 	}
+	DBG2(DBG_CFG, "    loaded certificate from '%s'", path);
 	this->creds->add_cert(this->creds, TRUE, cert);
 }
 
 /**
+ * Load a public key from path for the given identity
+ */
+static void load_public_key(private_cmd_creds_t *this, char *path, char *identity)
+{
+	certificate_t *cert;
+	public_key_t *pubkey;
+	key_type_t type = KEY_ANY;
+	identification_t *id;
+
+	DBG2(DBG_CFG, "  load_public_key_with_id(%s, %s)", path, identity);
+	if (identity)
+		{
+		id = identification_create_from_string(identity);
+		}
+	else
+		{
+		id = identification_create_from_encoding(ID_ANY, chunk_empty);
+		}
+	if (strpfx(path, "%smartcard"))
+	{
+		smartcard_format_t format;
+		char module[SC_PART_LEN], keyid[SC_PART_LEN];
+		u_int slot;
+
+		format = parse_smartcard(path, &slot, module, keyid);
+		if (format != SC_FORMAT_INVALID)
+		{
+			pubkey = (public_key_t*)load_from_smartcard_with_id(format,
+					slot, module, keyid, CRED_PUBLIC_KEY, KEY_RSA, id);
+			if (!pubkey)
+			{
+				DBG1(DBG_CFG, "  loading public key for \"%Y\" from '%s' failed",
+				 	id, path);
+				id->destroy(id);
+				exit(1);
+			}
+			cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+									  CERT_TRUSTED_PUBKEY,
+									  BUILD_PUBLIC_KEY, pubkey,
+									  BUILD_SUBJECT, id,
+									  BUILD_END);
+			type = pubkey->get_type(pubkey);
+			pubkey->destroy(pubkey);
+		}
+	}
+	else
+	{
+		pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
+									BUILD_FROM_FILE, path, BUILD_END);
+		if (pubkey)
+		{
+			cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+									  CERT_TRUSTED_PUBKEY,
+									  BUILD_PUBLIC_KEY, pubkey,
+									  BUILD_SUBJECT, id,
+									  BUILD_END);
+			type = pubkey->get_type(pubkey);
+			pubkey->destroy(pubkey);
+		}
+		// cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
+		// 						BUILD_FROM_FILE, path, BUILD_SUBJECT, id, BUILD_END);
+		// if (cert)
+		// {
+		// 	pubkey = cert->get_public_key(cert);
+		// 	type = pubkey->get_type(pubkey);
+		// 	pubkey->destroy(pubkey);
+		// }
+	}
+	if (!cert)
+	{
+		DBG1(DBG_CFG, "  loading public key for \"%Y\" from '%s' failed",
+		 	id, path);
+		id->destroy(id);
+		exit(1);
+	}
+	this->creds->add_cert(this->creds, TRUE, cert);
+	DBG2(DBG_CFG, "    loaded %N public key for \"%Y\" from '%s'", key_type_names, type, id, path);
+	id->destroy(id);
+}
+
+/**
  * Load a private key of given kind from path
  */
 static void load_key(private_cmd_creds_t *this, key_type_t type, char *path)
 {
 	private_key_t *privkey;
 
-	privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
-								 BUILD_FROM_FILE, path, BUILD_END);
+	DBG2(DBG_CFG, "  load_key(%N, %s)", key_type_names, type, path);
+	if (strpfx(path, "%smartcard"))
+	{
+		smartcard_format_t format;
+		char module[SC_PART_LEN], keyid[SC_PART_LEN];
+		u_int slot;
+
+		format = parse_smartcard(path, &slot, module, keyid);
+		if (format == SC_FORMAT_INVALID)
+		{
+			DBG1(DBG_CFG, "loading %N private key from '%s' failed: invalid format", key_type_names, type, path);
+			exit(1);
+			/* unlock: smartcard needs the pin */
+		}
+		else
+		{
+			privkey = (private_key_t*)load_from_smartcard(format,
+						slot, module, keyid, CRED_PRIVATE_KEY, KEY_ANY);
+		}
+	}
+	else
+	{
+		privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+									 BUILD_FROM_FILE, path, BUILD_END);
+	}
 	if (!privkey)
 	{
-		DBG1(DBG_CFG, "loading %N private key from '%s' failed",
-			 key_type_names, type, path);
+		DBG1(DBG_CFG, "loading %N private key from '%s' failed", key_type_names, type, path);
 		exit(1);
 	}
+	DBG2(DBG_CFG, "    loaded %N private key from '%s'", key_type_names, type, path);
 	this->creds->add_key(this->creds, privkey);
 }
 
@@ -240,9 +543,18 @@
 		case CMD_OPT_PKCS12:
 			load_pkcs12(this, arg);
 			break;
+		case CMD_OPT_LOCAL_PK:
+			this->local_pk = arg;
+			break;
+		case CMD_OPT_REMOTE_PK:
+			this->remote_pk = arg;
+			break;
 		case CMD_OPT_IDENTITY:
 			this->identity = arg;
 			break;
+		case CMD_OPT_REMOTE_IDENTITY:
+			this->remote_identity = arg;
+			break;
 		case CMD_OPT_AGENT:
 			this->agent = arg ?: getenv("SSH_AUTH_SOCK");
 			if (!this->agent)
@@ -260,6 +572,18 @@
 		/* only do this once */
 		this->agent = NULL;
 	}
+	if (this->local_pk && this->identity)
+	{
+		load_public_key(this, this->local_pk, this->identity);
+		/* only do this once */
+		this->local_pk = NULL;
+	}
+	if (this->remote_pk && this->remote_identity)
+	{
+		load_public_key(this, this->remote_pk, this->remote_identity);
+		/* only do this once */
+		this->remote_pk = NULL;
+	}
 	return TRUE;
 }
 
--- src/charon-cmd/cmd/cmd_options.c.orig	2016-04-22 22:01:35.000000000 +0200
+++ src/charon-cmd/cmd/cmd_options.c	2017-09-22 14:49:06.000000000 +0200
@@ -48,6 +48,10 @@
 	  "PKCS#12 file with private key and certificates to use for ", {
 		"authentication and trust chain validation"
 	}},
+	{ CMD_OPT_LOCAL_PK, "local-pk", required_argument, "path",
+	  "local public key for authentication", {}},
+	{ CMD_OPT_REMOTE_PK, "remote-pk", required_argument, "path",
+	  "remote public key for authentication", {}},
 	{ CMD_OPT_AGENT, "agent", optional_argument, "socket",
 	  "use SSH agent for authentication. If socket is not specified", {
 		"it is read from the SSH_AUTH_SOCK environment variable",
@@ -67,5 +71,16 @@
 		"  ikev2-pub, ikev2-eap, ikev2-pub-eap",
 		"  ikev1-pub[-am], ikev1-xauth[-am],",
 		"  ikev1-xauth-psk[-am], ikev1-hybrid[-am]",
+		"  ikev1-psk[-am]",
 	}},
+	{ CMD_OPT_MODE_CONFIG, "modeconfig", required_argument, "modeconfig",
+	  "set modeconfig mode (pull, push, off, default: pull)", {}},
+	{ CMD_OPT_VIRTUAL_IP, "virtual-ip", required_argument, "addr",
+	  "virtual IP to set for our side", {}},
+	{ CMD_OPT_TRANSPORT_MODE, "transport", no_argument, "",
+	  "set transport mode (default is tunnel mode)", {}},
+	{ CMD_OPT_L2TP, "l2tp", no_argument, "",
+	  "L2TP mode sets UDP/L2TP port traffic selector", {}},
+	{ CMD_OPT_FRAGMENTATION, "fragmentation", no_argument, "",
+	  "turn on fragmentation (default is off)", {}},
 };
--- src/charon-cmd/cmd/cmd_options.h.orig	2016-04-22 22:01:35.000000000 +0200
+++ src/charon-cmd/cmd/cmd_options.h	2017-09-22 14:16:15.000000000 +0200
@@ -42,6 +42,8 @@
 	CMD_OPT_CERT,
 	CMD_OPT_RSA,
 	CMD_OPT_PKCS12,
+	CMD_OPT_LOCAL_PK,
+	CMD_OPT_REMOTE_PK,
 	CMD_OPT_AGENT,
 	CMD_OPT_LOCAL_TS,
 	CMD_OPT_REMOTE_TS,
@@ -49,7 +51,12 @@
 	CMD_OPT_AH_PROPOSAL,
 	CMD_OPT_ESP_PROPOSAL,
 	CMD_OPT_PROFILE,
-
+	CMD_OPT_MODE_CONFIG,
+	CMD_OPT_VIRTUAL_IP,
+	CMD_OPT_TRANSPORT_MODE,
+	CMD_OPT_L2TP,
+	CMD_OPT_FRAGMENTATION,
+	
 	CMD_OPT_COUNT
 };
 
