summaryrefslogtreecommitdiff
path: root/src/charon-cmd/cmd
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2013-08-25 15:37:26 +0200
committerYves-Alexis Perez <corsac@debian.org>2013-08-25 15:37:26 +0200
commit6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 (patch)
tree009fc492961e13860d2a4bc2de8caf2bbe2975e7 /src/charon-cmd/cmd
parentc83921a2b566aa9d55d8ccc7258f04fca6292ee6 (diff)
downloadvyos-strongswan-6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349.tar.gz
vyos-strongswan-6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349.zip
Imported Upstream version 5.1.0
Diffstat (limited to 'src/charon-cmd/cmd')
-rw-r--r--src/charon-cmd/cmd/cmd_connection.c498
-rw-r--r--src/charon-cmd/cmd/cmd_connection.h60
-rw-r--r--src/charon-cmd/cmd/cmd_creds.c291
-rw-r--r--src/charon-cmd/cmd/cmd_creds.h55
-rw-r--r--src/charon-cmd/cmd/cmd_options.c65
-rw-r--r--src/charon-cmd/cmd/cmd_options.h76
6 files changed, 1045 insertions, 0 deletions
diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c
new file mode 100644
index 000000000..5c459f99f
--- /dev/null
+++ b/src/charon-cmd/cmd/cmd_connection.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "cmd_connection.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include <utils/debug.h>
+#include <processing/jobs/callback_job.h>
+#include <threading/thread.h>
+#include <daemon.h>
+
+typedef enum profile_t profile_t;
+typedef struct private_cmd_connection_t private_cmd_connection_t;
+
+/**
+ * Connection profiles we support
+ */
+enum profile_t {
+ PROF_UNDEF,
+ PROF_V2_PUB,
+ PROF_V2_EAP,
+ PROF_V2_PUB_EAP,
+ PROF_V1_PUB,
+ PROF_V1_PUB_AM,
+ PROF_V1_XAUTH,
+ PROF_V1_XAUTH_AM,
+ PROF_V1_XAUTH_PSK,
+ PROF_V1_XAUTH_PSK_AM,
+ PROF_V1_HYBRID,
+ PROF_V1_HYBRID_AM,
+};
+
+ENUM(profile_names, PROF_V2_PUB, PROF_V1_HYBRID_AM,
+ "ikev2-pub",
+ "ikev2-eap",
+ "ikev2-pub-eap",
+ "ikev1-pub",
+ "ikev1-pub-am",
+ "ikev1-xauth",
+ "ikev1-xauth-am",
+ "ikev1-xauth-psk",
+ "ikev1-xauth-psk-am",
+ "ikev1-hybrid",
+ "ikev1-hybrid-am",
+);
+
+/**
+ * Private data of an cmd_connection_t object.
+ */
+struct private_cmd_connection_t {
+
+ /**
+ * Public cmd_connection_t interface.
+ */
+ cmd_connection_t public;
+
+ /**
+ * Process ID to terminate on failure
+ */
+ pid_t pid;
+
+ /**
+ * List of local traffic selectors
+ */
+ linked_list_t *local_ts;
+
+ /**
+ * List of remote traffic selectors
+ */
+ linked_list_t *remote_ts;
+
+ /**
+ * Hostname to connect to
+ */
+ char *host;
+
+ /**
+ * Server identity, or NULL to use host
+ */
+ char *server;
+
+ /**
+ * Local identity
+ */
+ char *identity;
+
+ /**
+ * XAuth/EAP identity
+ */
+ char *xautheap;
+
+ /**
+ * Is a private key configured
+ */
+ bool key_seen;
+
+ /**
+ * Selected connection profile
+ */
+ profile_t profile;
+};
+
+/**
+ * Shut down application
+ */
+static void terminate(pid_t pid)
+{
+ kill(pid, SIGUSR1);
+}
+
+/**
+ * Create peer config with associated ike config
+ */
+static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this)
+{
+ ike_cfg_t *ike_cfg;
+ peer_cfg_t *peer_cfg;
+ u_int16_t local_port, remote_port = IKEV2_UDP_PORT;
+ ike_version_t version = IKE_ANY;
+ bool aggressive = FALSE;
+
+ switch (this->profile)
+ {
+ case PROF_UNDEF:
+ case PROF_V2_PUB:
+ case PROF_V2_EAP:
+ case PROF_V2_PUB_EAP:
+ version = IKEV2;
+ break;
+ case PROF_V1_PUB_AM:
+ case PROF_V1_XAUTH_AM:
+ case PROF_V1_XAUTH_PSK_AM:
+ case PROF_V1_HYBRID_AM:
+ aggressive = TRUE;
+ /* FALL */
+ case PROF_V1_PUB:
+ case PROF_V1_XAUTH:
+ case PROF_V1_XAUTH_PSK:
+ case PROF_V1_HYBRID:
+ version = IKEV1;
+ break;
+ }
+
+ 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", FALSE, local_port,
+ this->host, FALSE, remote_port, FRAGMENTATION_NO, 0);
+ ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+ peer_cfg = peer_cfg_create("cmd", ike_cfg,
+ CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */
+ 36000, 0, /* rekey 10h, reauth none */
+ 600, 600, /* jitter, over 10min */
+ TRUE, aggressive, /* mobike, aggressive */
+ 30, 0, /* DPD delay, timeout */
+ FALSE, NULL, NULL); /* mediation */
+ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
+
+ return peer_cfg;
+}
+
+/**
+ * Add a single auth cfg of given class to peer cfg
+ */
+static void add_auth_cfg(private_cmd_connection_t *this, peer_cfg_t *peer_cfg,
+ bool local, auth_class_t class)
+{
+ identification_t *id;
+ auth_cfg_t *auth;
+
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_AUTH_CLASS, class);
+ if (local)
+ {
+ id = identification_create_from_string(this->identity);
+ if (this->xautheap)
+ {
+ switch (class)
+ {
+ case AUTH_CLASS_EAP:
+ auth->add(auth, AUTH_RULE_EAP_IDENTITY,
+ identification_create_from_string(this->xautheap));
+ break;
+ case AUTH_CLASS_XAUTH:
+ auth->add(auth, AUTH_RULE_XAUTH_IDENTITY,
+ identification_create_from_string(this->xautheap));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (this->server)
+ {
+ id = identification_create_from_string(this->server);
+ }
+ else
+ {
+ id = identification_create_from_string(this->host);
+ }
+ auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, TRUE);
+ }
+ auth->add(auth, AUTH_RULE_IDENTITY, id);
+ peer_cfg->add_auth_cfg(peer_cfg, auth, local);
+}
+
+/**
+ * Attach authentication configs to peer config
+ */
+static bool add_auth_cfgs(private_cmd_connection_t *this, peer_cfg_t *peer_cfg)
+{
+ if (this->profile == PROF_UNDEF)
+ {
+ if (this->key_seen)
+ {
+ this->profile = PROF_V2_PUB;
+ }
+ else
+ {
+ this->profile = PROF_V2_EAP;
+ }
+ }
+ switch (this->profile)
+ {
+ case PROF_V2_PUB:
+ case PROF_V2_PUB_EAP:
+ case PROF_V1_PUB:
+ case PROF_V1_XAUTH:
+ case PROF_V1_PUB_AM:
+ case PROF_V1_XAUTH_AM:
+ if (!this->key_seen)
+ {
+ DBG1(DBG_CFG, "missing private key for profile %N",
+ profile_names, this->profile);
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (this->profile)
+ {
+ case PROF_V2_PUB:
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
+ add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY);
+ break;
+ case PROF_V2_EAP:
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_EAP);
+ add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY);
+ break;
+ case PROF_V2_PUB_EAP:
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_EAP);
+ add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY);
+ break;
+ case PROF_V1_PUB:
+ case PROF_V1_PUB_AM:
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
+ add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY);
+ break;
+ case PROF_V1_XAUTH:
+ case PROF_V1_XAUTH_AM:
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY);
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH);
+ add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY);
+ break;
+ case PROF_V1_XAUTH_PSK:
+ case PROF_V1_XAUTH_PSK_AM:
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PSK);
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH);
+ add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PSK);
+ break;
+ case PROF_V1_HYBRID:
+ case PROF_V1_HYBRID_AM:
+ add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH);
+ add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY);
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Attach child config to peer config
+ */
+static child_cfg_t* create_child_cfg(private_cmd_connection_t *this)
+{
+ child_cfg_t *child_cfg;
+ traffic_selector_t *ts;
+ lifetime_cfg_t lifetime = {
+ .time = {
+ .life = 10800 /* 3h */,
+ .rekey = 10200 /* 2h50min */,
+ .jitter = 300 /* 5min */
+ }
+ };
+
+ child_cfg = child_cfg_create("cmd", &lifetime,
+ NULL, FALSE, MODE_TUNNEL, /* updown, hostaccess */
+ ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
+ 0, 0, NULL, NULL, 0);
+ child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
+ while (this->local_ts->remove_first(this->local_ts, (void**)&ts) == SUCCESS)
+ {
+ child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
+ }
+ if (this->remote_ts->get_count(this->remote_ts) == 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);
+ this->remote_ts->insert_last(this->remote_ts, ts);
+ }
+ while (this->remote_ts->remove_first(this->remote_ts,
+ (void**)&ts) == SUCCESS)
+ {
+ child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+ }
+
+ return child_cfg;
+}
+
+/**
+ * Initiate the configured connection
+ */
+static job_requeue_t initiate(private_cmd_connection_t *this)
+{
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg;
+ pid_t pid = this->pid;
+
+ if (!this->host)
+ {
+ DBG1(DBG_CFG, "unable to initiate, missing --host option");
+ terminate(pid);
+ return JOB_REQUEUE_NONE;
+ }
+ if (!this->identity)
+ {
+ DBG1(DBG_CFG, "unable to initiate, missing --identity option");
+ terminate(pid);
+ return JOB_REQUEUE_NONE;
+ }
+
+ peer_cfg = create_peer_cfg(this);
+
+ if (!add_auth_cfgs(this, peer_cfg))
+ {
+ peer_cfg->destroy(peer_cfg);
+ terminate(pid);
+ return JOB_REQUEUE_NONE;
+ }
+
+ child_cfg = create_child_cfg(this);
+ peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg));
+
+ if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
+ controller_cb_empty, NULL, 0) != SUCCESS)
+ {
+ terminate(pid);
+ }
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Create a traffic selector from string, add to list
+ */
+static void add_ts(private_cmd_connection_t *this,
+ linked_list_t *list, char *string)
+{
+ traffic_selector_t *ts;
+
+ ts = traffic_selector_create_from_cidr(string, 0, 0, 65535);
+ if (!ts)
+ {
+ DBG1(DBG_CFG, "invalid traffic selector: %s", string);
+ exit(1);
+ }
+ list->insert_last(list, ts);
+}
+
+/**
+ * Parse profile name identifier
+ */
+static void set_profile(private_cmd_connection_t *this, char *name)
+{
+ int profile;
+
+ profile = enum_from_name(profile_names, name);
+ if (profile == -1)
+ {
+ DBG1(DBG_CFG, "unknown connection profile: %s", name);
+ exit(1);
+ }
+ this->profile = profile;
+}
+
+METHOD(cmd_connection_t, handle, bool,
+ private_cmd_connection_t *this, cmd_option_type_t opt, char *arg)
+{
+ switch (opt)
+ {
+ case CMD_OPT_HOST:
+ this->host = arg;
+ break;
+ case CMD_OPT_REMOTE_IDENTITY:
+ this->server = arg;
+ break;
+ case CMD_OPT_IDENTITY:
+ this->identity = arg;
+ break;
+ case CMD_OPT_EAP_IDENTITY:
+ case CMD_OPT_XAUTH_USER:
+ this->xautheap = arg;
+ break;
+ case CMD_OPT_RSA:
+ case CMD_OPT_AGENT:
+ case CMD_OPT_PKCS12:
+ this->key_seen = TRUE;
+ break;
+ case CMD_OPT_LOCAL_TS:
+ add_ts(this, this->local_ts, arg);
+ break;
+ case CMD_OPT_REMOTE_TS:
+ add_ts(this, this->remote_ts, arg);
+ break;
+ case CMD_OPT_PROFILE:
+ set_profile(this, arg);
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(cmd_connection_t, destroy, void,
+ private_cmd_connection_t *this)
+{
+ this->local_ts->destroy_offset(this->local_ts,
+ offsetof(traffic_selector_t, destroy));
+ this->remote_ts->destroy_offset(this->remote_ts,
+ offsetof(traffic_selector_t, destroy));
+ free(this);
+}
+
+/**
+ * See header
+ */
+cmd_connection_t *cmd_connection_create()
+{
+ private_cmd_connection_t *this;
+
+ INIT(this,
+ .public = {
+ .handle = _handle,
+ .destroy = _destroy,
+ },
+ .pid = getpid(),
+ .local_ts = linked_list_create(),
+ .remote_ts = linked_list_create(),
+ .profile = PROF_UNDEF,
+ );
+
+ /* 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(
+ (callback_job_cb_t)initiate, this, NULL,
+ (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
+
+ return &this->public;
+}
diff --git a/src/charon-cmd/cmd/cmd_connection.h b/src/charon-cmd/cmd/cmd_connection.h
new file mode 100644
index 000000000..221802617
--- /dev/null
+++ b/src/charon-cmd/cmd/cmd_connection.h
@@ -0,0 +1,60 @@
+/*
+ * 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 charon-cmd charon-cmd
+ *
+ * @defgroup cmd cmd
+ * @ingroup charon-cmd
+ *
+ * @defgroup cmd_connection cmd_connection
+ * @{ @ingroup cmd
+ */
+
+#ifndef CMD_CONNECTION_H_
+#define CMD_CONNECTION_H_
+
+#include <library.h>
+
+#include "cmd_options.h"
+
+typedef struct cmd_connection_t cmd_connection_t;
+
+/**
+ * Connection definition to construct and initiate.
+ */
+struct cmd_connection_t {
+
+ /**
+ * Handle a command line option.
+ *
+ * @param opt option to handle
+ * @param arg option argument
+ * @return TRUE if option handled
+ */
+ bool (*handle)(cmd_connection_t *this, cmd_option_type_t opt, char *arg);
+
+ /**
+ * Destroy a cmd_connection_t.
+ */
+ void (*destroy)(cmd_connection_t *this);
+};
+
+/**
+ * Create a cmd_connection instance.
+ */
+cmd_connection_t *cmd_connection_create();
+
+#endif /** CMD_CONNECTION_H_ @}*/
diff --git a/src/charon-cmd/cmd/cmd_creds.c b/src/charon-cmd/cmd/cmd_creds.c
new file mode 100644
index 000000000..526ff7c9c
--- /dev/null
+++ b/src/charon-cmd/cmd/cmd_creds.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "cmd_creds.h"
+
+#include <unistd.h>
+
+#include <utils/debug.h>
+#include <credentials/sets/mem_cred.h>
+#include <credentials/containers/pkcs12.h>
+#include <credentials/sets/callback_cred.h>
+
+typedef struct private_cmd_creds_t private_cmd_creds_t;
+
+/**
+ * Private data of an cmd_creds_t object.
+ */
+struct private_cmd_creds_t {
+
+ /**
+ * Public cmd_creds_t interface.
+ */
+ cmd_creds_t public;
+
+ /**
+ * Reused in-memory credential set
+ */
+ mem_cred_t *creds;
+
+ /**
+ * Callback credential set to get secrets
+ */
+ callback_cred_t *cb;
+
+ /**
+ * Already prompted for password?
+ */
+ bool prompted;
+
+ /**
+ * Path to ssh-agent socket
+ */
+ char *agent;
+
+ /**
+ * Local identity
+ */
+ char *identity;
+};
+
+/**
+ * Callback function to prompt for secret
+ */
+static shared_key_t* callback_shared(private_cmd_creds_t *this,
+ shared_key_type_t type,
+ identification_t *me, identification_t *other,
+ id_match_t *match_me, id_match_t *match_other)
+{
+ shared_key_t *shared;
+ char *label, *pwd;
+
+ if (this->prompted)
+ {
+ return NULL;
+ }
+ switch (type)
+ {
+ case SHARED_EAP:
+ label = "EAP password: ";
+ break;
+ case SHARED_IKE:
+ label = "Preshared Key: ";
+ break;
+ case SHARED_PRIVATE_KEY_PASS:
+ label = "Password: ";
+ break;
+ default:
+ return NULL;
+ }
+ pwd = getpass(label);
+ if (!pwd || strlen(pwd) == 0)
+ {
+ return NULL;
+ }
+ this->prompted = TRUE;
+ if (match_me)
+ {
+ *match_me = ID_MATCH_PERFECT;
+ }
+ if (match_other)
+ {
+ *match_other = ID_MATCH_PERFECT;
+ }
+ shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
+ /* cache password in case it is required more than once */
+ this->creds->add_shared(this->creds, shared, NULL);
+ return shared->get_ref(shared);
+}
+
+/**
+ * Load a trusted certificate from path
+ */
+static void load_cert(private_cmd_creds_t *this, char *path)
+{
+ certificate_t *cert;
+
+ 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);
+ }
+ this->creds->add_cert(this->creds, TRUE, cert);
+}
+
+/**
+ * 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);
+ if (!privkey)
+ {
+ DBG1(DBG_CFG, "loading %N private key from '%s' failed",
+ key_type_names, type, path);
+ exit(1);
+ }
+ this->creds->add_key(this->creds, privkey);
+}
+
+/**
+ * Load a private and public key via ssh-agent
+ */
+static void load_agent(private_cmd_creds_t *this)
+{
+ private_key_t *privkey;
+ public_key_t *pubkey;
+ identification_t *id;
+ certificate_t *cert;
+
+ privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
+ BUILD_AGENT_SOCKET, this->agent, BUILD_END);
+ if (!privkey)
+ {
+ DBG1(DBG_CFG, "failed to load private key from ssh-agent");
+ exit(1);
+ }
+ pubkey = privkey->get_public_key(privkey);
+ if (!pubkey)
+ {
+ DBG1(DBG_CFG, "failed to load public key from ssh-agent");
+ privkey->destroy(privkey);
+ exit(1);
+ }
+ id = identification_create_from_string(this->identity);
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+ CERT_TRUSTED_PUBKEY, BUILD_PUBLIC_KEY, pubkey,
+ BUILD_SUBJECT, id, BUILD_END);
+ pubkey->destroy(pubkey);
+ id->destroy(id);
+ if (!cert)
+ {
+ DBG1(DBG_CFG, "failed to create certificate for ssh-agent public key");
+ privkey->destroy(privkey);
+ exit(1);
+ }
+ this->creds->add_cert(this->creds, TRUE, cert);
+ this->creds->add_key(this->creds, privkey);
+}
+
+/**
+ * Load a PKCS#12 file from path
+ */
+static void load_pkcs12(private_cmd_creds_t *this, char *path)
+{
+ enumerator_t *enumerator;
+ certificate_t *cert;
+ private_key_t *key;
+ container_t *container;
+ pkcs12_t *pkcs12;
+
+ container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS12,
+ BUILD_FROM_FILE, path, BUILD_END);
+ if (!container)
+ {
+ DBG1(DBG_CFG, "loading PKCS#12 file '%s' failed", path);
+ exit(1);
+ }
+ pkcs12 = (pkcs12_t*)container;
+ enumerator = pkcs12->create_cert_enumerator(pkcs12);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
+ }
+ enumerator->destroy(enumerator);
+ enumerator = pkcs12->create_key_enumerator(pkcs12);
+ while (enumerator->enumerate(enumerator, &key))
+ {
+ this->creds->add_key(this->creds, key->get_ref(key));
+ }
+ enumerator->destroy(enumerator);
+ container->destroy(container);
+}
+
+METHOD(cmd_creds_t, handle, bool,
+ private_cmd_creds_t *this, cmd_option_type_t opt, char *arg)
+{
+ switch (opt)
+ {
+ case CMD_OPT_CERT:
+ load_cert(this, arg);
+ break;
+ case CMD_OPT_RSA:
+ load_key(this, KEY_RSA, arg);
+ break;
+ case CMD_OPT_PKCS12:
+ load_pkcs12(this, arg);
+ break;
+ case CMD_OPT_IDENTITY:
+ this->identity = arg;
+ break;
+ case CMD_OPT_AGENT:
+ this->agent = arg ?: getenv("SSH_AUTH_SOCK");
+ if (!this->agent)
+ {
+ DBG1(DBG_CFG, "no ssh-agent socket defined");
+ exit(1);
+ }
+ break;
+ default:
+ return FALSE;
+ }
+ if (this->agent && this->identity)
+ {
+ load_agent(this);
+ /* only do this once */
+ this->agent = NULL;
+ }
+ return TRUE;
+}
+
+METHOD(cmd_creds_t, destroy, void,
+ private_cmd_creds_t *this)
+{
+ lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
+ lib->credmgr->remove_set(lib->credmgr, &this->cb->set);
+ this->creds->destroy(this->creds);
+ this->cb->destroy(this->cb);
+ free(this);
+}
+
+/**
+ * See header
+ */
+cmd_creds_t *cmd_creds_create()
+{
+ private_cmd_creds_t *this;
+
+ INIT(this,
+ .public = {
+ .handle = _handle,
+ .destroy = _destroy,
+ },
+ .creds = mem_cred_create(),
+ );
+ this->cb = callback_cred_create_shared((void*)callback_shared, this);
+
+ lib->credmgr->add_set(lib->credmgr, &this->creds->set);
+ lib->credmgr->add_set(lib->credmgr, &this->cb->set);
+
+ return &this->public;
+}
diff --git a/src/charon-cmd/cmd/cmd_creds.h b/src/charon-cmd/cmd/cmd_creds.h
new file mode 100644
index 000000000..053e596a5
--- /dev/null
+++ b/src/charon-cmd/cmd/cmd_creds.h
@@ -0,0 +1,55 @@
+/*
+ * 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 cmd_creds cmd_creds
+ * @{ @ingroup cmd
+ */
+
+#ifndef CMD_CREDS_H_
+#define CMD_CREDS_H_
+
+#include <library.h>
+
+#include "cmd_options.h"
+
+typedef struct cmd_creds_t cmd_creds_t;
+
+/**
+ * Credential backend providing certificates, private keys and shared secrets.
+ */
+struct cmd_creds_t {
+
+ /**
+ * Handle a command line options related to credentials.
+ *
+ * @param opt option to handle
+ * @param arg option argument
+ * @return TRUE if option handled
+ */
+ bool (*handle)(cmd_creds_t *this, cmd_option_type_t opt, char *arg);
+
+ /**
+ * Destroy a cmd_creds_t.
+ */
+ void (*destroy)(cmd_creds_t *this);
+};
+
+/**
+ * Create a cmd_creds instance.
+ */
+cmd_creds_t *cmd_creds_create();
+
+#endif /** CMD_CREDS_H_ @}*/
diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c
new file mode 100644
index 000000000..597ccda1f
--- /dev/null
+++ b/src/charon-cmd/cmd/cmd_options.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "cmd_options.h"
+
+#include <getopt.h>
+
+/**
+ * See header.
+ */
+cmd_option_t cmd_options[CMD_OPT_COUNT] = {
+ { CMD_OPT_HELP, "help", no_argument, "",
+ "print this usage information and exit", {}},
+ { CMD_OPT_VERSION, "version", no_argument, "",
+ "show version information and exit", {}},
+ { CMD_OPT_DEBUG, "debug", required_argument, "level",
+ "set the default log level (-1..4, default: 1)", {}},
+ { CMD_OPT_HOST, "host", required_argument, "hostname",
+ "DNS name or address to connect to", {}},
+ { CMD_OPT_IDENTITY, "identity", required_argument, "identity",
+ "identity the client uses for the IKE exchange", {}},
+ { CMD_OPT_EAP_IDENTITY, "eap-identity", required_argument, "eap-identity",
+ "identity the client uses for EAP authentication", {}},
+ { CMD_OPT_XAUTH_USER, "xauth-username", required_argument, "xauth-username",
+ "username the client uses for XAuth authentication", {}},
+ { CMD_OPT_REMOTE_IDENTITY, "remote-identity", required_argument, "identity",
+ "server identity to expect, defaults to host", {}},
+ { CMD_OPT_CERT, "cert", required_argument, "path",
+ "certificate for authentication or trust chain validation", {}},
+ { CMD_OPT_RSA, "rsa", required_argument, "path",
+ "RSA private key to use for authentication", {}},
+ { CMD_OPT_PKCS12, "p12", required_argument, "path",
+ "PKCS#12 file with private key and certificates to use for ", {
+ "authentication and trust chain validation"
+ }},
+ { 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",
+ }},
+ { CMD_OPT_LOCAL_TS, "local-ts", required_argument, "subnet",
+ "additional traffic selector to propose for our side", {}},
+ { CMD_OPT_REMOTE_TS, "remote-ts", required_argument, "subnet",
+ "traffic selector to propose for remote side", {}},
+ { CMD_OPT_PROFILE, "profile", required_argument, "name",
+ "authentication profile to use, where name is one of:", {
+ " ikev2-pub, ikev2-eap, ikev2-pub-eap",
+ " ikev1-pub[-am], ikev1-xauth[-am],",
+ " ikev1-xauth-psk[-am], ikev1-hybrid[-am]",
+ }},
+};
diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h
new file mode 100644
index 000000000..6b8b04cdf
--- /dev/null
+++ b/src/charon-cmd/cmd/cmd_options.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 cmd_option cmd_option
+ * @{ @ingroup cmd
+ */
+
+#ifndef CMD_OPTION_H_
+#define CMD_OPTION_H_
+
+typedef struct cmd_option_t cmd_option_t;
+typedef enum cmd_option_type_t cmd_option_type_t;
+
+/**
+ * Command line options
+ */
+enum cmd_option_type_t {
+ CMD_OPT_HELP,
+ CMD_OPT_VERSION,
+ CMD_OPT_DEBUG,
+ CMD_OPT_HOST,
+ CMD_OPT_IDENTITY,
+ CMD_OPT_EAP_IDENTITY,
+ CMD_OPT_XAUTH_USER,
+ CMD_OPT_REMOTE_IDENTITY,
+ CMD_OPT_CERT,
+ CMD_OPT_RSA,
+ CMD_OPT_PKCS12,
+ CMD_OPT_AGENT,
+ CMD_OPT_LOCAL_TS,
+ CMD_OPT_REMOTE_TS,
+ CMD_OPT_PROFILE,
+
+ CMD_OPT_COUNT
+};
+
+/**
+ * Command line arguments, similar to "struct option", but with descriptions
+ */
+struct cmd_option_t {
+ /** option identifier */
+ cmd_option_type_t id;
+ /** long option name */
+ const char *name;
+ /** takes argument */
+ int has_arg;
+ /** decription of argument */
+ const char *arg;
+ /** short description to option */
+ const char *desc;
+ /** additional description lines */
+ const char *lines[12];
+};
+
+/**
+ * Registered CMD options.
+ */
+extern cmd_option_t cmd_options[CMD_OPT_COUNT];
+
+#endif /** CMD_OPTION_H_ @}*/