aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2006-05-04 07:55:42 +0000
committerMartin Willi <martin@strongswan.org>2006-05-04 07:55:42 +0000
commit9820c0e208fa5c7467fb89b1bda86ced6962e02f (patch)
treeff3ac9872ada7a2b52358d797395574211ff9c68
parent8744148f554275cbeb1510018971cc936dd9aeb2 (diff)
downloadstrongswan-9820c0e208fa5c7467fb89b1bda86ced6962e02f.tar.bz2
strongswan-9820c0e208fa5c7467fb89b1bda86ced6962e02f.tar.xz
- applied patch from andreas
- pem loading - secrets file parsing - ikev2 testcase - some other additions here and there
-rw-r--r--CHANGES15
-rw-r--r--INSTALL106
-rw-r--r--README.pluto2
-rw-r--r--src/charon/charon/config/credentials/local_credential_store.c152
-rw-r--r--src/charon/charon/config/credentials/local_credential_store.h9
-rw-r--r--src/charon/charon/daemon.c2
-rw-r--r--src/charon/charon/daemon.h15
-rwxr-xr-xsrc/charon/charon/threads/stroke_interface.c10
-rw-r--r--src/charon/lib/asn1/asn1.c55
-rwxr-xr-xsrc/charon/lib/asn1/pem.c205
-rwxr-xr-xsrc/charon/lib/asn1/pem.h8
-rw-r--r--src/charon/lib/asn1/ttodata.h2
-rw-r--r--src/charon/lib/crypto/rsa/rsa_private_key.c39
-rwxr-xr-xsrc/charon/lib/crypto/x509.c43
-rw-r--r--src/charon/lib/types.h5
-rw-r--r--src/charon/lib/utils/Makefile.utils6
-rw-r--r--src/charon/lib/utils/lexparser.c135
-rw-r--r--src/charon/lib/utils/lexparser.h57
-rw-r--r--src/charon/lib/utils/logger.c6
-rw-r--r--src/charon/stroke/stroke.c20
-rw-r--r--src/ipsec/distro.txt3
-rwxr-xr-xsrc/ipsec/ipsec.in83
-rw-r--r--src/pluto/connections.c11
-rw-r--r--src/pluto/kernel.c4
-rw-r--r--src/pluto/log.c6
-rw-r--r--src/pluto/state.c4
-rw-r--r--src/pluto/vendor.c3
-rw-r--r--src/pluto/vendor.h1
-rw-r--r--src/starter/confread.h8
-rw-r--r--src/starter/starter.c886
-rwxr-xr-xtesting/do-tests3
-rwxr-xr-xtesting/scripts/build-umlrootfs1
-rw-r--r--testing/tests/ikev2-net2net/description.txt6
-rw-r--r--testing/tests/ikev2-net2net/evaltest.dat5
-rw-r--r--testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.conf13
-rw-r--r--testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.d/certs/sunCert.pem24
-rw-r--r--testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.conf13
-rw-r--r--testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.d/certs/moonCert.pem24
-rw-r--r--testing/tests/ikev2-net2net/posttest.dat4
-rw-r--r--testing/tests/ikev2-net2net/pretest.dat7
-rw-r--r--testing/tests/ikev2-net2net/test.conf21
41 files changed, 1207 insertions, 815 deletions
diff --git a/CHANGES b/CHANGES
index e87a5da33..00aa01872 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,18 @@
+strongswan-4.0.0
+----------------
+
+- initial support of the IKEv2 protocol. Connections in
+ ipsec.conf designated by keyexchange=ikev2 are negotiated
+ by the new IKEv2 charon keying daemon whereas those marked
+ by keyexchange=ikev1 or the default keyexchange=ike are
+ handled thy the IKEv1 pluto keying daemon. Currently only
+ a limited subset of functions are available with IKEv2
+ (Default AES encryption, authentication based on locally
+ imported X.509 certificates, unencrypted private RSA keys
+ in PKCS#1 file format, limited functionality of the ipsec
+ status command).
+
+
strongswan-2.7.0
----------------
diff --git a/INSTALL b/INSTALL
index 0ed541936..df334ffc7 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,5 +1,5 @@
---------------------------
- strongSwan - Installation
+ strongSwan - Installation
---------------------------
@@ -11,9 +11,7 @@ Contents
2.1 libcurl
2.2 OpenLDAP
2.3 PKCS#11 smartcard library modules
- 3. Building strongSwan with a Linux 2.4 kernel
- 4. Updating strongSwan with a Linux 2.4 kernel
- 5. Building strongSwan with a Linux 2.6 kernel
+ 3. Building and running strongSwan with a Linux 2.6 kernel
1. Required packages
@@ -125,9 +123,9 @@ Contents
in "Makefile.inc"
# Uncomment this line if using OpenSC <= 0.9.6
- PKCS11_DEFAULT_LIB=\"/usr/lib/pkcs11/opensc-pkcs11.so\"
+ # PKCS11_DEFAULT_LIB=\"/usr/lib/pkcs11/opensc-pkcs11.so\"
# Uncomment tis line if using OpenSC >= 0.10.0
- #PKCS11_DEFAULT_LIB=\"usr/lib/opensc-pkcs11.so\"
+ PKCS11_DEFAULT_LIB=\"usr/lib/opensc-pkcs11.so\"
This default path to the easily-obtainable OpenSC library module can be
simply overridden during run-time by specifying an alternative path in
@@ -141,80 +139,9 @@ Contents
USE="smartcard usb -pam -X" emerge strongswan
-3. Building strongSwan with a Linux 2.4 kernel
- -------------------------------------------
- * Building strongSwan with a Linux 2.4 kernel requires the presence of the
- matching kernel sources referenced via the symbolic link /usr/src/linux.
- The use of the vanilla kernel sources from ftp.kernel.org is strongly
- recommended.
-
- Before building strongSwan you must have compiled the kernel sources at
- least once:
-
- make menuconfig; make dep; make bzImage; make modules
-
- * Now change into the strongswan-2.x.x source directory.
-
- First uncomment any desired compile options in "programs/pluto/Makefile"
- (see section 2. Optional packages).
-
- Then in the top source directory type
-
- make menumod
-
- This command applies an ESP_IN_UDP encapsulation patch which is required
- for NAT-Traversal to the kernel sources.
-
- In the "Networking options" menu set
-
- <M> IP Security Protocol (strongSwan IPsec)
-
- in order to build KLIPS as a loadable kernel module "ipsec.o". Do not
- forget to save the modified configuration file when leaving "menumod".
-
- The strongSwan userland programs are now automatically built and
- installed, whereas the ipsec.o kernel module and the crypto modules
- are only built and must be installed with the command
-
- make minstall
-
- * If you intend to use the NAT-Traversal feature then you must compile the
- patched kernel sources again by executing
-
- make bzImage
-
- and then install and boot the modified kernel.
-
- * Next add your connections to "/etc/ipsec.conf" and start strongSwan with
-
- ipsec setup start
-
-
-4. Updating strongSwan with a Linux 2.4 kernel
- -------------------------------------------
-
- * If you have already successfully installed strongSwan and want to update
- to a newer version then the following shortcut can be taken:
-
- First uncomment any desired compile options in "programs/pluto/Makefile"
- (see section 2. Optional packages).
-
- Then in the strongwan-2.x.x top directory type
-
- make programs; make install
-
- followed by
-
- make module; make minstall
-
- * You can then start the updated strongSwan version with
-
- ipsec setup restart
-
-
-5. Building strongSwan with a Linux 2.6 kernel
- -------------------------------------------
+3. Building and running strongSwan with a Linux 2.6 kernel
+ -------------------------------------------------------
* Because the Linux 2.6 kernel comes with a built-in native IPsec stack,
you won't need to build the strongSwan kernel modules. Please make sure
@@ -225,25 +152,30 @@ Contents
o esp4
o ipcomp
o xfrm_user
+ o xfrm_tunnel
Also the built-in kernel Cryptoapi modules with selected encryption and
hash algorithms should be available.
- * First uncomment any desired compile options in "programs/pluto/Makefile"
- (see section 2. Optional packages).
+ * First select any desired compile options in "Makefile.inc" (see section 2.
+ Optional packages). Then in the strongwan-4.x.x top directory type
- Then in the strongwan-2.x.x top directory type
-
- make programs
+ make
followed by
make install
- * Next add your connections to "etc/ipsec.conf" and start strongSwan with
+ * Next add your connections to "/etc/ipsec.conf" and your secrets to
+ "/etc/ipsec.secrets". Connections that are to be negotiated by the new
+ IKEv2 charon keying daemon should be designated by "keyexchange=ikev2" and
+ those by the IKEv1 pluto keying daemon either by "keyexchange=ikev1" or
+ the default "keyexchange=ike".
+
+ * At last start strongSwan with
- ipsec setup start
+ ipsec start
-----------------------------------------------------------------------------
-This file is RCSID $Id: INSTALL,v 1.8 2006/01/22 16:22:23 as Exp $
+This file is RCSID $Id: INSTALL,v 1.9 2006/05/01 16:02:37 as Exp $
diff --git a/README.pluto b/README.pluto
index d40d887a3..e9ebfee02 100644
--- a/README.pluto
+++ b/README.pluto
@@ -2650,7 +2650,7 @@ and can be used when the following prerequisites are fulfilled:
- Linux 2.4.x kernel, KLIPS IPsec stack, and arbitrary iptables version.
Filtering of tunneled traffic is based on ipsecN interfaces.
- - Linux 2.4.16 kernel or newer, native NETKEY IPsec stack, and
+ - Linux 2.6.16 kernel or newer, native NETKEY IPsec stack, and
iptables-1.3.5 or newer. Filtering of tunneled traffic is based on
IPsec policy matching rules.
diff --git a/src/charon/charon/config/credentials/local_credential_store.c b/src/charon/charon/config/credentials/local_credential_store.c
index dc6cb6c50..e4fa1aa26 100644
--- a/src/charon/charon/config/credentials/local_credential_store.c
+++ b/src/charon/charon/config/credentials/local_credential_store.c
@@ -22,13 +22,16 @@
#include <sys/stat.h>
#include <dirent.h>
+#include <string.h>
#include "local_credential_store.h"
+#include <utils/lexparser.h>
#include <utils/linked_list.h>
#include <utils/logger_manager.h>
#include <crypto/x509.h>
+#define PATH_BUF 256
typedef struct key_entry_t key_entry_t;
@@ -138,9 +141,9 @@ static rsa_private_key_t *get_rsa_private_key(private_local_credential_store_t *
}
/**
- * Implements local_credential_store_t.load_private_keys
+ * Implements local_credential_store_t.load_certificates
*/
-static void load_certificates(private_local_credential_store_t *this, char *path)
+static void load_certificates(private_local_credential_store_t *this, const char *path)
{
struct dirent* entry;
struct stat stb;
@@ -154,7 +157,8 @@ static void load_certificates(private_local_credential_store_t *this, char *path
}
while ((entry = readdir(dir)) != NULL)
{
- char file[256];
+ char file[PATH_BUF];
+
snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
if (stat(file, &stb) == -1)
@@ -168,7 +172,6 @@ static void load_certificates(private_local_credential_store_t *this, char *path
if (cert)
{
this->certificates->insert_last(this->certificates, (void*)cert);
- this->logger->log(this->logger, CONTROL|LEVEL1, "loaded certificate \"%s\"", file);
}
else
{
@@ -218,55 +221,118 @@ static identification_t *get_id_for_private_key(private_local_credential_store_t
/**
* Implements local_credential_store_t.load_private_keys
*/
-static void load_private_keys(private_local_credential_store_t *this, char *path)
+static void load_private_keys(private_local_credential_store_t *this, const char *secretsfile, const char *defaultpath)
{
- struct dirent* entry;
- struct stat stb;
- DIR* dir;
- rsa_private_key_t *key;
-
- dir = opendir(path);
- if (dir == NULL) {
- this->logger->log(this->logger, ERROR, "error opening private key directory \"%s\"", path);
- return;
- }
- while ((entry = readdir(dir)) != NULL)
+ FILE *fd = fopen(secretsfile, "r");
+
+ if (fd)
{
- char file[256];
- snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
-
- if (stat(file, &stb) == -1)
- {
- continue;
- }
- /* try to parse all regular files */
- if (stb.st_mode & S_IFREG)
+ int bytes;
+ int line_nr = 0;
+ chunk_t chunk, src, line;
+
+ this->logger->log(this->logger, CONTROL, "loading secrets from \"%s\"", secretsfile);
+
+ fseek(fd, 0, SEEK_END);
+ chunk.len = ftell(fd);
+ rewind(fd);
+ chunk.ptr = malloc(chunk.len);
+ bytes = fread(chunk.ptr, 1, chunk.len, fd);
+ fclose(fd);
+
+ src = chunk;
+
+ while (fetchline(&src, &line))
{
- key = rsa_private_key_create_from_file(file, NULL);
- if (key)
+ chunk_t ids, token;
+
+ line_nr++;
+
+ if (!eat_whitespace(&line))
{
- key_entry_t *entry;
- identification_t *id = get_id_for_private_key(this, key);
- if (!id)
+ continue;
+ }
+ if (!extract_token(&ids, ':', &line))
+ {
+ this->logger->log(this->logger, ERROR, "line %d: missing ':' separator", line_nr);
+ goto error;
+ }
+ if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
+ {
+ this->logger->log(this->logger, ERROR, "line %d: missing token", line_nr);
+ goto error;
+ }
+ if (match("RSA", &token))
+ {
+ char path[PATH_BUF];
+ chunk_t filename;
+
+ err_t ugh = extract_value(&filename, &line);
+
+ if (ugh != NULL)
+ {
+ this->logger->log(this->logger, ERROR, "line %d: %s", line_nr, ugh);
+ goto error;
+ }
+ if (filename.len == 0)
+ {
+ this->logger->log(this->logger, ERROR,
+ "line %d: empty filename", line_nr);
+ goto error;
+ }
+ if (*filename.ptr == '/')
+ {
+ /* absolute path name */
+ snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
+ }
+ else
{
- this->logger->log(this->logger, ERROR,
- "no certificate found for private key \"%s\", skipped", file);
- key->destroy(key);
- continue;
+ /* relative path name */
+ snprintf(path, sizeof(path), "%s/%.*s", defaultpath, filename.len, filename.ptr);
}
- entry = malloc_thing(key_entry_t);
- entry->key = key;
- entry->id = id;
- this->private_keys->insert_last(this->private_keys, (void*)entry);
- this->logger->log(this->logger, CONTROL|LEVEL1, "loaded private key \"%s\"", file);
+
+ rsa_private_key_t *key = rsa_private_key_create_from_file(path, NULL);
+ if (key)
+ {
+ key_entry_t *entry;
+ identification_t *id = get_id_for_private_key(this, key);
+
+ if (!id)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no certificate found for private key \"%s\", skipped", path);
+ key->destroy(key);
+ continue;
+ }
+ entry = malloc_thing(key_entry_t);
+ entry->key = key;
+ entry->id = id;
+ this->private_keys->insert_last(this->private_keys, (void*)entry);
+ }
+ }
+ else if (match("PSK", &token))
+ {
+
+ }
+ else if (match("PIN", &token))
+ {
+
}
else
{
- this->logger->log(this->logger, ERROR, "private key \"%s\" invalid, skipped", file);
+ this->logger->log(this->logger, ERROR,
+ "line %d: token must be either RSA, PSK, or PIN",
+ line_nr, token.len);
+ goto error;
}
}
+error:
+ free(chunk.ptr);
+ }
+ else
+ {
+ this->logger->log(this->logger, ERROR, "could not open file '%s'", secretsfile);
}
- closedir(dir);
}
/**
@@ -302,8 +368,8 @@ local_credential_store_t * local_credential_store_create()
this->public.credential_store.get_shared_secret = (status_t(*)(credential_store_t*,identification_t*,chunk_t*))get_shared_secret;
this->public.credential_store.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,identification_t*))get_rsa_private_key;
this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key;
- this->public.load_certificates = (void(*)(local_credential_store_t*,char*))load_certificates;
- this->public.load_private_keys = (void(*)(local_credential_store_t*,char*))load_private_keys;
+ this->public.load_certificates = (void(*)(local_credential_store_t*,const char*))load_certificates;
+ this->public.load_private_keys = (void(*)(local_credential_store_t*,const char*, const char*))load_private_keys;
this->public.credential_store.destroy = (void(*)(credential_store_t*))destroy;
/* private variables */
diff --git a/src/charon/charon/config/credentials/local_credential_store.h b/src/charon/charon/config/credentials/local_credential_store.h
index ab9ef88d7..64438b378 100644
--- a/src/charon/charon/config/credentials/local_credential_store.h
+++ b/src/charon/charon/config/credentials/local_credential_store.h
@@ -57,7 +57,7 @@ struct local_credential_store_t {
* @param this calling object
* @param path directory to load certificates from
*/
- void (*load_certificates) (local_credential_store_t *this, char *path);
+ void (*load_certificates) (local_credential_store_t *this, const char *path);
/**
* @brief Loads RSA private keys from a folder.
@@ -66,10 +66,11 @@ struct local_credential_store_t {
* other gets ignored. Further, a certificate for the specific private
* key must already be loaded to get the ID from.
*
- * @param this calling object
- * @param path directory to load keys from
+ * @param this calling object
+ * @param secretsfile file where secrets are stored
+ * @param defaultpath default directory for private keys
*/
- void (*load_private_keys) (local_credential_store_t *this, char *path);
+ void (*load_private_keys) (local_credential_store_t *this, const char *secretsfile, const char *defaultpath);
};
/**
diff --git a/src/charon/charon/daemon.c b/src/charon/charon/daemon.c
index 4b0ea54e8..f3d9fecdb 100644
--- a/src/charon/charon/daemon.c
+++ b/src/charon/charon/daemon.c
@@ -179,7 +179,7 @@ static void initialize(private_daemon_t *this)
/* load keys & certs */
cred_store->load_certificates(cred_store, CERTIFICATE_DIR);
- cred_store->load_private_keys(cred_store, PRIVATE_KEY_DIR);
+ cred_store->load_private_keys(cred_store, SECRETS_FILE, PRIVATE_KEY_DIR);
/* start building threads, we are multi-threaded NOW */
diff --git a/src/charon/charon/daemon.h b/src/charon/charon/daemon.h
index 5aee21fdb..5cad1339b 100644
--- a/src/charon/charon/daemon.h
+++ b/src/charon/charon/daemon.h
@@ -203,11 +203,18 @@
#define PID_FILE "/var/run/charon.pid"
/**
+ * Configuration directory
+ *
+ * @ingroup charon
+ */
+#define CONFIG_DIR "/etc"
+
+/**
* Directory of IPsec relevant files
*
* @ingroup charon
*/
-#define IPSEC_DIR "/etc/ipsec.d"
+#define IPSEC_DIR CONFIG_DIR "/ipsec.d"
/**
* Directory for private keys
@@ -223,6 +230,12 @@
*/
#define CERTIFICATE_DIR IPSEC_DIR "/certs"
+/**
+ * Secrets files
+ *
+ * @ingroup charon
+ */
+#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
typedef struct daemon_t daemon_t;
diff --git a/src/charon/charon/threads/stroke_interface.c b/src/charon/charon/threads/stroke_interface.c
index eeb14cd94..0a7ba80a6 100755
--- a/src/charon/charon/threads/stroke_interface.c
+++ b/src/charon/charon/threads/stroke_interface.c
@@ -241,8 +241,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
my_id = my_id->clone(my_id);
cert->destroy(cert);
this->logger->log(this->logger, CONTROL,
- "defined a valid certificate, using its ID \"%s\"",
- my_id->get_string(my_id));
+ "valid certificate with ID \"%s\"",
+ my_id->get_string(my_id));
}
}
if (msg->add_conn.other.cert)
@@ -257,8 +257,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
other_id = other_id->clone(other_id);
cert->destroy(cert);
this->logger->log(this->logger, CONTROL,
- "defined a valid certificate, using its ID \"%s\"",
- other_id->get_string(other_id));
+ "valid certificate with ID \"%s\"",
+ other_id->get_string(other_id));
}
}
@@ -308,7 +308,7 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name);
if (connection == NULL)
{
- this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name);
+ this->stroke_logger->log(this->stroke_logger, ERROR, "no connection named \"%s\"", msg->initiate.name);
}
else
{
diff --git a/src/charon/lib/asn1/asn1.c b/src/charon/lib/asn1/asn1.c
index c847461b6..e894999fb 100644
--- a/src/charon/lib/asn1/asn1.c
+++ b/src/charon/lib/asn1/asn1.c
@@ -21,8 +21,6 @@
#include <utils/logger_manager.h>
-static logger_t *logger;
-
/* Names of the months */
static const char* months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -87,7 +85,18 @@ static const asn1Object_t algorithmIdentifierObjects[] = {
#define ALGORITHM_ID_PARAMETERS 2
#define ALGORITHM_ID_ROOF 3
-/*
+static logger_t *logger = NULL;
+
+/**
+ * initializes the ASN.1 logger
+ */
+static void asn1_init_logger()
+{
+ if (logger == NULL)
+ logger = logger_manager->get_logger(logger_manager, ASN1);
+}
+
+/**
* return the ASN.1 encoded algorithm identifier
*/
chunk_t asn1_algorithmIdentifier(int oid)
@@ -109,7 +118,7 @@ chunk_t asn1_algorithmIdentifier(int oid)
}
}
-/*
+/**
* If the oid is listed in the oid_names table then the corresponding
* position in the oid_names table is returned otherwise -1 is returned
*/
@@ -141,7 +150,7 @@ int known_oid(chunk_t object)
return -1;
}
-/*
+/**
* Decodes the length in bytes of an ASN.1 object
*/
u_int asn1_length(chunk_t *blob)
@@ -188,7 +197,7 @@ u_int asn1_length(chunk_t *blob)
return len;
}
-/*
+/**
* determines if a character string is of type ASN.1 printableString
*/
bool is_printablestring(chunk_t str)
@@ -205,9 +214,9 @@ bool is_printablestring(chunk_t str)
return TRUE;
}
-/*
+/**
* Display a date either in local or UTC time
- * TODO: Does not seem to be thread save
+ * TODO: Does not seem to be thread safe
*/
char* timetoa(const time_t *time, bool utc)
{
@@ -225,7 +234,7 @@ char* timetoa(const time_t *time, bool utc)
return buf;
}
-/*
+/**
* Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
*/
time_t asn1totime(const chunk_t *utctime, asn1_t type)
@@ -300,19 +309,20 @@ time_t asn1totime(const chunk_t *utctime, asn1_t type)
return mktime(&t) - timezone - tz_offset;
}
-/*
+/**
* Initializes the internal context of the ASN.1 parser
*/
void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit)
{
- logger = logger_manager->get_logger(logger_manager, ASN1);
+ asn1_init_logger();
+
ctx->blobs[0] = blob;
ctx->level0 = level0;
ctx->implicit = implicit;
memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));
}
-/*
+/**
* print the value of an ASN.1 simple object
*/
static void debug_asn1_simple_object(chunk_t object, asn1_t type)
@@ -348,7 +358,7 @@ static void debug_asn1_simple_object(chunk_t object, asn1_t type)
logger->log_chunk(logger, RAW|LEVEL1, "", object);
}
-/*
+/**
* Parses and extracts the next ASN.1 object
*/
bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx)
@@ -479,7 +489,7 @@ bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *objec
return TRUE;
}
-/*
+/**
* parse an ASN.1 simple type
*/
bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name)
@@ -515,7 +525,7 @@ bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const c
return TRUE;
}
-/*
+/**
* extracts an algorithmIdentifier
*/
int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
@@ -558,6 +568,8 @@ bool is_asn1(chunk_t blob)
u_int len;
u_char tag = *blob.ptr;
+ asn1_init_logger();
+
if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
{
logger->log(logger, ERROR|LEVEL2, " file content is not binary ASN.1");
@@ -572,7 +584,7 @@ bool is_asn1(chunk_t blob)
return TRUE;
}
-/*
+/**
* codes ASN.1 lengths up to a size of 16'777'215 bytes
*/
void code_asn1_length(size_t length, chunk_t *code)
@@ -605,7 +617,7 @@ void code_asn1_length(size_t length, chunk_t *code)
}
}
-/*
+/**
* build an empty asn.1 object with tag and length fields already filled in
*/
u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen)
@@ -634,7 +646,7 @@ u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen)
return pos;
}
-/*
+/**
* build a simple ASN.1 object
*/
chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
@@ -648,7 +660,8 @@ chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
return object;
}
-/* Build an ASN.1 object from a variable number of individual chunks.
+/**
+ * Build an ASN.1 object from a variable number of individual chunks.
* Depending on the mode, chunks either are moved ('m') or copied ('c').
*/
chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
@@ -696,7 +709,7 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
return construct;
}
-/*
+/**
* convert a MP integer into a DER coded ASN.1 object
*/
chunk_t asn1_integer_from_mpz(const mpz_t value)
@@ -709,7 +722,7 @@ chunk_t asn1_integer_from_mpz(const mpz_t value)
return asn1_wrap(ASN1_INTEGER, "m", n);
}
-/*
+/**
* convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
*/
chunk_t timetoasn1(const time_t *time, asn1_t type)
diff --git a/src/charon/lib/asn1/pem.c b/src/charon/lib/asn1/pem.c
index b02268dd9..d3a6986eb 100755
--- a/src/charon/lib/asn1/pem.c
+++ b/src/charon/lib/asn1/pem.c
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2005 Jan Hutter, Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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
@@ -21,14 +20,27 @@
#include <stddef.h>
#include <sys/types.h>
+#include "asn1.h"
#include "pem.h"
#include "ttodata.h"
+#include <utils/lexparser.h>
+#include <utils/logger_manager.h>
#include <crypto/hashers/hasher.h>
#include <crypto/crypters/crypter.h>
+static logger_t *logger = NULL;
-/*
+/**
+ * initializes the PEM logger
+ */
+static void pem_init_logger()
+{
+ if (logger == NULL)
+ logger = logger_manager->get_logger(logger_manager, ASN1);
+}
+
+/**
* check the presence of a pattern in a character string
*/
static bool present(const char* pattern, chunk_t* ch)
@@ -44,15 +56,7 @@ static bool present(const char* pattern, chunk_t* ch)
return FALSE;
}
-/*
- * compare string with chunk
- */
-static bool match(const char *pattern, const chunk_t *ch)
-{
- return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
-}
-
-/*
+/**
* find a boundary of the form -----tag name-----
*/
static bool find_boundary(const char* tag, chunk_t *line)
@@ -73,6 +77,8 @@ static bool find_boundary(const char* tag, chunk_t *line)
{
if (present("-----", line))
{
+ logger->log(logger, CONTROL|LEVEL2,
+ " -----%s %.*s-----", tag, (int)name.len, name.ptr);
return TRUE;
}
line->ptr++; line->len--; name.len++;
@@ -81,92 +87,15 @@ static bool find_boundary(const char* tag, chunk_t *line)
}
/*
- * eat whitespace
- */
-static void eat_whitespace(chunk_t *src)
-{
- while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
- {
- src->ptr++; src->len--;
- }
-}
-
-/*
- * extracts a token ending with a given termination symbol
- */
-static bool extract_token(chunk_t *token, char termination, chunk_t *src)
-{
- u_char *eot = memchr(src->ptr, termination, src->len);
-
- /* initialize empty token */
- *token = CHUNK_INITIALIZER;
-
- if (eot == NULL) /* termination symbol not found */
- {
- return FALSE;
- }
-
- /* extract token */
- token->ptr = src->ptr;
- token->len = (u_int)(eot - src->ptr);
-
- /* advance src pointer after termination symbol */
- src->ptr = eot + 1;
- src->len -= (token->len + 1);
-
- return TRUE;
-}
-
-/*
- * extracts a name: value pair from the PEM header
- */
-static bool extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line)
-{
- /* extract name */
- if (!extract_token(name,':', line))
- {
- return FALSE;
- }
-
- eat_whitespace(line);
-
- /* extract value */
- *value = *line;
- return TRUE;
-}
-
-/*
- * fetches a new line terminated by \n or \r\n
- */
-static bool fetchline(chunk_t *src, chunk_t *line)
-{
- if (src->len == 0) /* end of src reached */
- return FALSE;
-
- if (extract_token(line, '\n', src))
- {
- if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
- line->len--; /* remove optional \r */
- }
- else /*last line ends without newline */
- {
- *line = *src;
- src->ptr += src->len;
- src->len = 0;
- }
- return TRUE;
-}
-
-/*
* decrypts a DES-EDE-CBC encrypted data block
*/
-static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase)
+static err_t pem_decrypt(chunk_t *blob, chunk_t *iv, const char *passphrase)
{
hasher_t *hasher;
crypter_t *crypter;
chunk_t hash;
chunk_t decrypted;
- chunk_t pass = {passphrase, strlen(passphrase)};
+ chunk_t pass = {(char*)passphrase, strlen(passphrase)};
chunk_t key = {alloca(24), 24};
u_int8_t padding, *last_padding_pos, *first_padding_pos;
@@ -203,11 +132,11 @@ static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase)
while (--last_padding_pos > first_padding_pos)
{
if (*last_padding_pos != padding)
- return FALSE;
+ return "invalid passphrase";
}
/* remove padding */
blob->len -= padding;
- return TRUE;
+ return NULL;
}
/* Converts a PEM encoded file into its binary form
@@ -215,7 +144,7 @@ static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase)
* RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
* RFC 934 Message Encapsulation, January 1985
*/
-status_t pemtobin(chunk_t *blob, char *pass)
+err_t pem_to_bin(chunk_t *blob, const char *passphrase, bool *pgp)
{
typedef enum {
PEM_PRE = 0,
@@ -244,6 +173,8 @@ status_t pemtobin(chunk_t *blob, char *pass)
iv.ptr = iv_buf;
iv.len = 0;
+ pem_init_logger();
+
while (fetchline(&src, &line))
{
if (state == PEM_PRE)
@@ -277,8 +208,9 @@ status_t pemtobin(chunk_t *blob, char *pass)
continue;
}
- /* we are looking for a name: value pair */
- if (!extract_parameter(&name, &value, &line))
+ /* we are looking for a parameter: value pair */
+ logger->log(logger, CONTROL|LEVEL2, " %.*s", (int)line.len, line.ptr);
+ if (!extract_parameter_value(&name, &value, &line))
continue;
if (match("Proc-Type", &name) && *value.ptr == '4')
@@ -294,12 +226,12 @@ status_t pemtobin(chunk_t *blob, char *pass)
/* we support DES-EDE3-CBC encrypted files, only */
if (!match("DES-EDE3-CBC", &dek))
- return NOT_SUPPORTED;
+ return "encryption algorithm not supported";
eat_whitespace(&value);
ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len);
if (ugh)
- return PARSE_ERROR;
+ return "error in IV";
iv.len = len;
}
@@ -316,6 +248,17 @@ status_t pemtobin(chunk_t *blob, char *pass)
data = line;
}
+ /* check for PGP armor checksum */
+ if (*data.ptr == '=')
+ {
+ *pgp = TRUE;
+ data.ptr++;
+ data.len--;
+ logger->log(logger, CONTROL|LEVEL2, " Armor checksum: %.*s",
+ (int)data.len, data.ptr);
+ continue;
+ }
+
ugh = ttodata(data.ptr, data.len, 64, dst.ptr, blob->len - dst.len, &len);
if (ugh)
{
@@ -334,10 +277,68 @@ status_t pemtobin(chunk_t *blob, char *pass)
blob->len = dst.len;
if (state != PEM_POST)
- return PARSE_ERROR;
+ return "file coded in unknown format, discarded";
+
+ return (encrypted)? pem_decrypt(blob, &iv, passphrase) : NULL;
+}
+
+/* load a coded key or certificate file with autodetection
+ * of binary DER or base64 PEM ASN.1 formats and armored PGP format
+ */
+bool pem_asn1_load_file(const char *filename, const char *passphrase,
+ const char *type, chunk_t *blob, bool *pgp)
+{
+ err_t ugh = NULL;
+
+ FILE *fd = fopen(filename, "r");
+
+ pem_init_logger();
+
+ if (fd)
+ {
+ int bytes;
+ fseek(fd, 0, SEEK_END );
+ blob->len = ftell(fd);
+ rewind(fd);
+ blob->ptr = malloc(blob->len);
+ bytes = fread(blob->ptr, 1, blob->len, fd);
+ fclose(fd);
+ logger->log(logger, CONTROL, "loaded %s file '%s' (%d bytes)", type, filename, bytes);
+
+ *pgp = FALSE;
+
+ /* try DER format */
+ if (is_asn1(*blob))
+ {
+ logger->log(logger, CONTROL|LEVEL1, " file coded in DER format");
+ return TRUE;
+ }
+
+ /* try PEM format */
+ ugh = pem_to_bin(blob, passphrase, pgp);
+
+ if (ugh == NULL)
+ {
+ if (*pgp)
+ {
+ logger->log(logger, CONTROL|LEVEL1, " file coded in armored PGP format");
+ return TRUE;
+ }
+ if (is_asn1(*blob))
+ {
+ logger->log(logger, CONTROL|LEVEL1, " file coded in PEM format");
+ return TRUE;
+ }
+ ugh = "file coded in unknown format, discarded";
+ }
- if (encrypted)
- return pem_decrypt(blob, &iv, pass);
+ /* a conversion error has occured */
+ logger->log(logger, ERROR, " %s", ugh);
+ chunk_free(blob);
+ }
else
- return SUCCESS;
+ {
+ logger->log(logger, ERROR, "could not open %s file '%s'", type, filename);
+ }
+ return FALSE;
}
diff --git a/src/charon/lib/asn1/pem.h b/src/charon/lib/asn1/pem.h
index a4332fd34..30621fa24 100755
--- a/src/charon/lib/asn1/pem.h
+++ b/src/charon/lib/asn1/pem.h
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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
@@ -20,6 +19,9 @@
#include <types.h>
-status_t pemtobin(chunk_t *blob, char *pass);
+err_t pem_to_bin(chunk_t *blob, const char *passphrase, bool *pgp);
+
+bool pem_asn1_load_file(const char *filename, const char *passphrase,
+ const char *type, chunk_t *blob, bool *pgp);
#endif /*PEM_H_*/
diff --git a/src/charon/lib/asn1/ttodata.h b/src/charon/lib/asn1/ttodata.h
index d57244ef5..b2b5adefd 100644
--- a/src/charon/lib/asn1/ttodata.h
+++ b/src/charon/lib/asn1/ttodata.h
@@ -22,8 +22,6 @@
#define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/
#define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */
-typedef const char *err_t; /* error message, or NULL for success */
-
err_t ttodata(const char *src, size_t srclen, int base, char *buf, size_t buflen, size_t *needed);
diff --git a/src/charon/lib/crypto/rsa/rsa_private_key.c b/src/charon/lib/crypto/rsa/rsa_private_key.c
index 358653f0e..86a38cbfe 100644
--- a/src/charon/lib/crypto/rsa/rsa_private_key.c
+++ b/src/charon/lib/crypto/rsa/rsa_private_key.c
@@ -29,6 +29,7 @@
#include <daemon.h>
#include <asn1/asn1.h>
+#include <asn1/pem.h>
/*
* Oids for hash algorithms are defined in
@@ -736,37 +737,17 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob)
/*
* see header
- * TODO: PEM files
*/
rsa_private_key_t *rsa_private_key_create_from_file(char *filename, char *passphrase)
{
- chunk_t chunk;
- struct stat stb;
- FILE *file;
- char *buffer;
-
- if (stat(filename, &stb) == -1)
- {
- return NULL;
- }
-
- buffer = alloca(stb.st_size);
-
- file = fopen(filename, "r");
- if (file == NULL)
- {
- return NULL;
- }
-
- if (fread(buffer, stb.st_size, 1, file) != 1)
- {
- fclose(file);
+ bool pgp = FALSE;
+ chunk_t chunk = CHUNK_INITIALIZER;
+ rsa_private_key_t *key = NULL;
+
+ if (!pem_asn1_load_file(filename, passphrase, "private key", &chunk, &pgp))
return NULL;
- }
- fclose(file);
-
- chunk.ptr = buffer;
- chunk.len = stb.st_size;
-
- return rsa_private_key_create_from_chunk(chunk);
+
+ key = rsa_private_key_create_from_chunk(chunk);
+ free(chunk.ptr);
+ return key;
}
diff --git a/src/charon/lib/crypto/x509.c b/src/charon/lib/crypto/x509.c
index 86a595618..91f9f191e 100755
--- a/src/charon/lib/crypto/x509.c
+++ b/src/charon/lib/crypto/x509.c
@@ -28,13 +28,11 @@
#include "x509.h"
#include <daemon.h>
-#include <asn1/asn1.h>
#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <asn1/pem.h>
#include <utils/logger_manager.h>
-typedef const char *err_t; /* error message, or NULL for success */
-
-
#define BUF_LEN 512
#define RSA_MIN_OCTETS (512 / 8)
#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits"
@@ -905,33 +903,14 @@ x509_t *x509_create_from_chunk(chunk_t chunk)
*/
x509_t *x509_create_from_file(char *filename)
{
- struct stat stb;
- FILE *file;
- char *buffer;
- chunk_t chunk;
-
- if (stat(filename, &stb) == -1)
- {
- return NULL;
- }
-
- buffer = alloca(stb.st_size);
-
- file = fopen(filename, "r");
- if (file == NULL)
- {
- return NULL;
- }
-
- if (fread(buffer, stb.st_size, 1, file) == -1)
- {
- fclose(file);
+ bool pgp = FALSE;
+ chunk_t chunk = CHUNK_INITIALIZER;
+ x509_t *cert = NULL;
+
+ if (!pem_asn1_load_file(filename, "", "certificate", &chunk, &pgp))
return NULL;
- }
- fclose(file);
-
- chunk.ptr = buffer;
- chunk.len = stb.st_size;
-
- return x509_create_from_chunk(chunk);
+
+ cert = x509_create_from_chunk(chunk);
+ free(chunk.ptr);
+ return cert;
}
diff --git a/src/charon/lib/types.h b/src/charon/lib/types.h
index 0e0782b31..4af9bc43d 100644
--- a/src/charon/lib/types.h
+++ b/src/charon/lib/types.h
@@ -37,6 +37,11 @@ typedef int bool;
#define FALSE 0
#define TRUE 1
+/**
+ * error message, or NULL for success
+ */
+typedef const char *err_t;
+
typedef enum status_t status_t;
/**
diff --git a/src/charon/lib/utils/Makefile.utils b/src/charon/lib/utils/Makefile.utils
index 1c82283d7..c04f3b1df 100644
--- a/src/charon/lib/utils/Makefile.utils
+++ b/src/charon/lib/utils/Makefile.utils
@@ -18,10 +18,14 @@ LIB_OBJS+= $(BUILD_DIR)leak_detective.o
$(BUILD_DIR)leak_detective.o : $(UTILS_DIR)leak_detective.c $(UTILS_DIR)leak_detective.h
$(CC) $(CFLAGS) -c -o $@ $<
+LIB_OBJS+= $(BUILD_DIR)lexparser.o
+$(BUILD_DIR)lexparser.o : $(UTILS_DIR)lexparser.c $(UTILS_DIR)lexparser.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
LIB_OBJS+= $(BUILD_DIR)linked_list.o
$(BUILD_DIR)linked_list.o : $(UTILS_DIR)linked_list.c $(UTILS_DIR)linked_list.h
$(CC) $(CFLAGS) -c -o $@ $<
-
+
LIB_OBJS+= $(BUILD_DIR)logger.o
$(BUILD_DIR)logger.o : $(UTILS_DIR)logger.c $(UTILS_DIR)logger.h
$(CC) $(CFLAGS) -c -o $@ $<
diff --git a/src/charon/lib/utils/lexparser.c b/src/charon/lib/utils/lexparser.c
new file mode 100644
index 000000000..e3bb3d1f9
--- /dev/null
+++ b/src/charon/lib/utils/lexparser.c
@@ -0,0 +1,135 @@
+/**
+ * @file lexparser.c
+ *
+ * @brief lexical parser for text-based configuration files
+ *
+ */
+
+/*
+ * Copyright (C) 2001-2006 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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 <string.h>
+
+#include "lexparser.h"
+
+
+/**
+ * eat whitespace
+ */
+bool eat_whitespace(chunk_t *src)
+{
+ while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
+ {
+ src->ptr++; src->len--;
+ }
+ return src->len > 0 && *src->ptr != '#';
+}
+
+/**
+ * compare string with chunk
+ */
+bool match(const char *pattern, const chunk_t *ch)
+{
+ return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
+}
+
+/**
+ * extracts a token ending with a given termination symbol
+ */
+bool extract_token(chunk_t *token, const char termination, chunk_t *src)
+{
+ u_char *eot = memchr(src->ptr, termination, src->len);
+
+ /* initialize empty token */
+ *token = CHUNK_INITIALIZER;
+
+ if (eot == NULL) /* termination symbol not found */
+ {
+ return FALSE;
+ }
+
+ /* extract token */
+ token->ptr = src->ptr;
+ token->len = (u_int)(eot - src->ptr);
+
+ /* advance src pointer after termination symbol */
+ src->ptr = eot + 1;
+ src->len -= (token->len + 1);
+
+ return TRUE;
+}
+
+/**
+ * fetches a new line terminated by \n or \r\n
+ */
+bool fetchline(chunk_t *src, chunk_t *line)
+{
+ if (src->len == 0) /* end of src reached */
+ return FALSE;
+
+ if (extract_token(line, '\n', src))
+ {
+ if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
+ line->len--; /* remove optional \r */
+ }
+ else /*last line ends without newline */
+ {
+ *line = *src;
+ src->ptr += src->len;
+ src->len = 0;
+ }
+ return TRUE;
+}
+
+err_t extract_value(chunk_t *value, chunk_t *line)
+{
+ char delimiter = ' ';
+
+ if (!eat_whitespace(line))
+ {
+ return "missing value";
+ }
+ if (*line->ptr == '\'' || *line->ptr == '"')
+ {
+ delimiter = *line->ptr;
+ line->ptr++; line->len--;
+ }
+ if (!extract_token(value, delimiter, line))
+ {
+ if (delimiter == ' ')
+ {
+ *value = *line;
+ }
+ else
+ {
+ return "missing second delimiter";
+ }
+ }
+ return NULL;
+}
+
+/**
+ * extracts a parameter: value pair
+ */
+err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line)
+{
+ /* extract name */
+ if (!extract_token(name,':', line))
+ {
+ return "missing ':'";
+ }
+
+ /* extract value */
+ return extract_value(value, line);
+}
diff --git a/src/charon/lib/utils/lexparser.h b/src/charon/lib/utils/lexparser.h
new file mode 100644
index 000000000..29c1bf701
--- /dev/null
+++ b/src/charon/lib/utils/lexparser.h
@@ -0,0 +1,57 @@
+/**
+ * @file lexparser.h
+ *
+ * @brief lexical parser for text-based configuration files
+ *
+ */
+
+/*
+ * Copyright (C) 2001-2006 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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 <types.h>
+
+/**
+ * @brief Eats whitespace
+ */
+bool eat_whitespace(chunk_t *src);
+
+/**
+ * @brief Compare null-terminated pattern with chunk
+ */
+bool match(const char *pattern, const chunk_t *ch);
+
+/**
+ * @brief Extracts a token ending with a given termination symbol
+ */
+bool extract_token(chunk_t *token, const char termination, chunk_t *src);
+
+/**
+ * @brief Fetches a new text line terminated by \n or \r\n
+ */
+bool fetchline(chunk_t *src, chunk_t *line);
+
+/**
+ * @brief Extracts a value that might be single or double quoted
+ */
+err_t extract_value(chunk_t *value, chunk_t *line);
+
+/**
+ * @brief extracts a name: value pair from a text line
+ */
+err_t extract_name_value(chunk_t *name, chunk_t *value, chunk_t *line);
+
+/**
+ * @brief extracts a parameter: value from a text line
+ */
+err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line);
diff --git a/src/charon/lib/utils/logger.c b/src/charon/lib/utils/logger.c
index fdaeddff0..151fbfd50 100644
--- a/src/charon/lib/utils/logger.c
+++ b/src/charon/lib/utils/logger.c
@@ -132,11 +132,15 @@ static void prepend_prefix(private_logger_t *this, log_level_t loglevel, const c
*/
static int get_priority(log_level_t loglevel)
{
+ if (loglevel & ERROR)
+ {
+ return LOG_AUTHPRIV|LOG_ERR;
+ }
if (loglevel & AUDIT)
{
return LOG_AUTHPRIV|LOG_INFO;
}
- return LOG_DAEMON|LOG_DEBUG;
+ return LOG_AUTHPRIV|LOG_DEBUG;
}
/**
diff --git a/src/charon/stroke/stroke.c b/src/charon/stroke/stroke.c
index 9ecda0413..7a734a05f 100644
--- a/src/charon/stroke/stroke.c
+++ b/src/charon/stroke/stroke.c
@@ -239,19 +239,21 @@ static void exit_usage(char *error)
int main(int argc, char *argv[])
{
int res;
+ char *op;
if (argc < 2)
{
exit_usage(NULL);
}
- if (strcmp(argv[1], "status") == 0 ||
- strcmp(argv[1], "statusall") == 0)
+ op = argv[1];
+
+ if (strcmp(op, "status") == 0 ||
+ strcmp(op, "statusall") == 0)
{
- res = show_status(argv[1], argc > 2 ? argv[2] : NULL);
+ res = show_status(op, argc > 2 ? argv[2] : NULL);
}
-
- else if (strcmp(argv[1], "up") == 0)
+ else if (strcmp(op, "up") == 0)
{
if (argc < 3)
{
@@ -259,7 +261,7 @@ int main(int argc, char *argv[])
}
res = initiate_connection(argv[2]);
}
- else if (strcmp(argv[1], "down") == 0)
+ else if (strcmp(op, "down") == 0)
{
if (argc < 3)
{
@@ -267,7 +269,7 @@ int main(int argc, char *argv[])
}
res = terminate_connection(argv[2]);
}
- else if (strcmp(argv[1], "add") == 0)
+ else if (strcmp(op, "add") == 0)
{
if (argc < 11)
{
@@ -279,7 +281,7 @@ int main(int argc, char *argv[])
argv[7], argv[8],
atoi(argv[9]), atoi(argv[10]));
}
- else if (strcmp(argv[1], "logtype") == 0)
+ else if (strcmp(op, "logtype") == 0)
{
if (argc < 5)
{
@@ -287,7 +289,7 @@ int main(int argc, char *argv[])
}
res = set_logtype(argv[2], argv[3], atoi(argv[4]));
}
- else if (strcmp(argv[1], "loglevel") == 0)
+ else if (strcmp(op, "loglevel") == 0)
{
if (argc < 4)
{
diff --git a/src/ipsec/distro.txt b/src/ipsec/distro.txt
index 80f4192a4..8c1ad8a38 100644
--- a/src/ipsec/distro.txt
+++ b/src/ipsec/distro.txt
@@ -1 +1,2 @@
-distributed by Andreas Steffen <andreas.steffen@strongswan.org>
+distributed by the Institute of Internet Technologies and Applications
+University of Applied Sciences Rapperswil, Switzerland (ITA-HSR)
diff --git a/src/ipsec/ipsec.in b/src/ipsec/ipsec.in
index 04156e8ae..1a5006eed 100755
--- a/src/ipsec/ipsec.in
+++ b/src/ipsec/ipsec.in
@@ -1,6 +1,7 @@
#! /bin/sh
# prefix command to run stuff from our programs directory
# Copyright (C) 1998-2002 Henry Spencer.
+# Copyright (C) 2006 Andreas Steffen
#
# 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
@@ -26,6 +27,7 @@ IPSEC_DIR="$IPSEC_LIBDIR"
export IPSEC_DIR IPSEC_CONFS IPSEC_LIBDIR IPSEC_EXECDIR
IPSEC_STARTER_PID="/var/run/starter.pid"
+IPSEC_PLUTO_PID="/var/run/pluto.pid"
IPSEC_CHARON_PID="/var/run/charon.pid"
# standardize PATH, and export it for everything else's benefit
@@ -123,10 +125,13 @@ case "$1" in
;;
down)
shift
- $IPSEC_EXECDIR/whack --name "$1" --terminate
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack --name "$1" --terminate
+ fi
if test -e $IPSEC_CHARON_PID
then
- $IPSEC_EXECDIR/stroke down "$1"
+ $IPSEC_EXECDIR/stroke down "$1"
fi
exit 0
;;
@@ -138,16 +143,22 @@ rereadcacerts|rereadaacerts|rereadocspcerts|\
rereadacerts|rereadcrls|rereadall)
op="$1"
shift
- $IPSEC_EXECDIR/whack "$@" "--$op"
- if test -e $IPSEC_CHARON_PID
+ if test -e $IPSEC_PLUTO_PID
then
- $IPSEC_EXECDIR/stroke "$op"
- fi
+ $IPSEC_EXECDIR/whack "$@" "--$op"
+ fi
+ #if test -e $IPSEC_CHARON_PID
+ #then
+ # $IPSEC_EXECDIR/stroke "$op"
+ #fi
exit 0
;;
ready)
shift
- $IPSEC_EXECDIR/whack --listen
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack --listen
+ fi
exit 0
;;
reload)
@@ -170,19 +181,28 @@ restart)
route|unroute)
op="$1"
shift
- $IPSEC_EXECDIR/whack --name "$1" "--$op"
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack --name "$1" "--$op"
+ fi
exit 0
;;
scencrypt|scdecrypt)
op="$1"
shift
- $IPSEC_EXECDIR/whack "--$op" "$@"
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack "--$op" "$@"
+ fi
exit 0
;;
secrets)
- $IPSEC_EXECDIR/whack --rereadsecrets
- exit 0
- ;;
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack --rereadsecrets
+ fi
+ exit 0
+ ;;
start)
shift
exec $IPSEC_EXECDIR/starter "$@"
@@ -192,17 +212,23 @@ status|statusall)
shift
if test $# -eq 0
then
- $IPSEC_EXECDIR/whack "--$op"
- if test -e $IPSEC_CHARON_PID
- then
- $IPSEC_EXECDIR/stroke "$op"
- fi
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack "--$op"
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_EXECDIR/stroke "$op"
+ fi
else
- $IPSEC_EXECDIR/whack --name "$1" "--$op"
- if test -e $IPSEC_CHARON_PID
- then
- $IPSEC_EXECDIR/stroke "$op" "$1"
- fi
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack --name "$1" "--$op"
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_EXECDIR/stroke "$op" "$1"
+ fi
fi
exit 0
;;
@@ -218,7 +244,10 @@ stop)
;;
up)
shift
- $IPSEC_EXECDIR/whack --name "$1" --initiate
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_EXECDIR/whack --name "$1" --initiate
+ fi
if test -e $IPSEC_CHARON_PID
then
$IPSEC_EXECDIR/stroke up "$1"
@@ -228,10 +257,10 @@ up)
update)
if test -e $IPSEC_STARTER_PID
then
- echo "Updating strongSwan IPsec configuration..." >&2
- kill -s HUP `cat $IPSEC_STARTER_PID`
+ echo "Updating strongSwan IPsec configuration..." >&2
+ kill -s HUP `cat $IPSEC_STARTER_PID`
else
- echo "ipsec starter is not running" >&2
+ echo "ipsec starter is not running" >&2
fi
exit 0
;;
@@ -241,7 +270,7 @@ version|--version)
echo "See \`ipsec --copyright' for copyright information."
if [ -f $IPSEC_LIBDIR/distro.txt ]
then
- cat $IPSEC_LIBDIR/distro.txt
+ cat $IPSEC_LIBDIR/distro.txt
fi
exit 0
;;
diff --git a/src/pluto/connections.c b/src/pluto/connections.c
index 263bdbd1e..6cf6a6a8b 100644
--- a/src/pluto/connections.c
+++ b/src/pluto/connections.c
@@ -11,7 +11,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: connections.c,v 1.42 2006/04/22 21:59:20 as Exp $
+ * RCSID $Id: connections.c,v 1.43 2006/04/29 18:16:02 as Exp $
*/
#include <string.h>
@@ -4022,7 +4022,7 @@ show_connections_status(bool all, const char *name)
/* sort it! */
qsort(array, count, sizeof(struct connection *), connection_compare_qsort);
- for (i=0; i<count; i++)
+ for (i = 0; i < count; i++)
{
const char *ifn;
char instance[1 + 10 + 1];
@@ -4076,7 +4076,7 @@ show_connections_status(bool all, const char *name)
if (c->spd.that.groups != NULL)
{
char buf[BUF_LEN];
-
+
format_groups(c->spd.that.groups, buf, BUF_LEN);
whack_log(RC_COMMENT
, "\"%s\"%s: groups: %s"
@@ -4097,7 +4097,7 @@ show_connections_status(bool all, const char *name)
, (unsigned long) c->sa_keying_tries);
/* show DPD parameters if defined */
-
+
if (c->dpd_action != DPD_ACTION_NONE)
whack_log(RC_COMMENT
, "\"%s\"%s: dpd_action: %s;"
@@ -4141,6 +4141,9 @@ show_connections_status(bool all, const char *name)
kernel_alg_show_connection(c, instance);
}
}
+ if (count > 0)
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+
pfree(array);
}
diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c
index 5d7c5f78a..d2070c0d4 100644
--- a/src/pluto/kernel.c
+++ b/src/pluto/kernel.c
@@ -12,7 +12,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: kernel.c,v 1.25 2006/04/17 14:58:09 as Exp $
+ * RCSID $Id: kernel.c,v 1.26 2006/04/29 18:16:02 as Exp $
*/
#include <stddef.h>
@@ -934,6 +934,8 @@ show_shunt_status(void)
, ourst, ourport, hist, hisport, sat, bs->transport_proto
, prio, bs->why);
}
+ if (bare_shunts != NULL)
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
}
/* Setup an IPsec route entry.
diff --git a/src/pluto/log.c b/src/pluto/log.c
index 137e92980..73ffceccd 100644
--- a/src/pluto/log.c
+++ b/src/pluto/log.c
@@ -12,7 +12,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: log.c,v 1.7 2005/07/11 18:33:45 as Exp $
+ * RCSID $Id: log.c,v 1.8 2006/04/29 18:16:02 as Exp $
*/
#include <stdio.h>
@@ -770,13 +770,11 @@ show_status(bool all, const char *name)
show_ifaces_status();
show_myid_status();
show_debug_status();
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
}
- whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
show_connections_status(all, name);
- whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
show_states_status(name);
#ifdef KLIPS
- whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
show_shunt_status();
#endif
}
diff --git a/src/pluto/state.c b/src/pluto/state.c
index 5957654e3..0781d2eb3 100644
--- a/src/pluto/state.c
+++ b/src/pluto/state.c
@@ -12,7 +12,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: state.c,v 1.12 2006/04/03 15:49:36 as Exp $
+ * RCSID $Id: state.c,v 1.13 2006/04/29 18:16:02 as Exp $
*/
#include <stdio.h>
@@ -902,6 +902,8 @@ show_states_status(const char *name)
if (IS_PHASE1(st->st_state))
show_pending_phase2(st->st_connection->host_pair, st);
}
+ if (count > 0)
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
/* free the array */
pfree(array);
diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c
index 51931c239..1616fed28 100644
--- a/src/pluto/vendor.c
+++ b/src/pluto/vendor.c
@@ -198,7 +198,8 @@ static struct vid_struct _vid_tab[] = {
/*
* strongSwan
*/
- DEC_MD5_VID(STRONGSWAN, "strongSwan 2.7.0")
+ DEC_MD5_VID(STRONGSWAN, "strongSwan 4.0.0")
+ DEC_MD5_VID(STRONGSWAN_2_7_0, "strongSwan 2.7.0")
DEC_MD5_VID(STRONGSWAN_2_6_4, "strongSwan 2.6.4")
DEC_MD5_VID(STRONGSWAN_2_6_3, "strongSwan 2.6.3")
DEC_MD5_VID(STRONGSWAN_2_6_2, "strongSwan 2.6.2")
diff --git a/src/pluto/vendor.h b/src/pluto/vendor.h
index d6b414be2..7c2030d76 100644
--- a/src/pluto/vendor.h
+++ b/src/pluto/vendor.h
@@ -76,6 +76,7 @@ enum known_vendorid {
VID_STRONGSWAN_2_6_2 = 55,
VID_STRONGSWAN_2_6_3 = 56,
VID_STRONGSWAN_2_6_4 = 57,
+ VID_STRONGSWAN_2_7_0 = 58,
/* 101 - 200 : NAT-Traversal */
VID_NATT_STENBERG_01 =101,
diff --git a/src/starter/confread.h b/src/starter/confread.h
index a3b1b7379..9793a55a5 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -40,6 +40,12 @@ typedef enum {
STATE_INVALID
} starter_state_t;
+typedef enum {
+ KEY_EXCHANGE_IKE,
+ KEY_EXCHANGE_IKEV1,
+ KEY_EXCHANGE_IKEV2
+} keyexchange_t;
+
typedef struct starter_end starter_end_t;
struct starter_end {
@@ -89,7 +95,7 @@ struct starter_conn {
startup_t startup;
starter_state_t state;
- int keyexchange;
+ keyexchange_t keyexchange;
lset_t policy;
time_t sa_ike_life_seconds;
time_t sa_ipsec_life_seconds;
diff --git a/src/starter/starter.c b/src/starter/starter.c
index 4b4e23fb3..1f857ce44 100644
--- a/src/starter/starter.c
+++ b/src/starter/starter.c
@@ -36,6 +36,7 @@
#include "confread.h"
#include "files.h"
#include "starterwhack.h"
+#include "starterstroke.h"
#include "invokepluto.h"
#include "invokecharon.h"
#include "netkey.h"
@@ -47,564 +48,583 @@
#define FLAG_ACTION_RELOAD 0x04
#define FLAG_ACTION_QUIT 0x08
#define FLAG_ACTION_LISTEN 0x10
-#ifdef IKEV2
#define FLAG_ACTION_START_CHARON 0x20
-#endif /* IKEV2 */
static unsigned int _action_ = 0;
static void
fsig(int signal)
{
- switch (signal)
- {
- case SIGCHLD:
+ switch (signal)
{
- int status;
- pid_t pid;
- char *name = NULL;
-
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
- {
- if (pid == starter_pluto_pid())
- name = " (Pluto)";
+ case SIGCHLD:
+ {
+ int status;
+ pid_t pid;
+ char *name = NULL;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ {
+ if (pid == starter_pluto_pid())
+ name = " (Pluto)";
#ifdef IKEV2
- if (pid == starter_charon_pid())
- name = " (Charon)";
+ if (pid == starter_charon_pid())
+ name = " (Charon)";
#endif /* IKEV2 */
- if (WIFSIGNALED(status))
- DBG(DBG_CONTROL,
- DBG_log("child %d%s has been killed by sig %d\n",
- pid, name?name:"", WTERMSIG(status))
- )
- else if (WIFSTOPPED(status))
- DBG(DBG_CONTROL,
- DBG_log("child %d%s has been stopped by sig %d\n",
- pid, name?name:"", WSTOPSIG(status))
- )
- else if (WIFEXITED(status))
- DBG(DBG_CONTROL,
- DBG_log("child %d%s has quit (exit code %d)\n",
- pid, name?name:"", WEXITSTATUS(status))
- )
- else
- DBG(DBG_CONTROL,
- DBG_log("child %d%s has quit", pid, name?name:"")
- )
-
- if (pid == starter_pluto_pid())
- starter_pluto_sigchild(pid);
+ if (WIFSIGNALED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has been killed by sig %d\n",
+ pid, name?name:"", WTERMSIG(status))
+ )
+ else if (WIFSTOPPED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has been stopped by sig %d\n",
+ pid, name?name:"", WSTOPSIG(status))
+ )
+ else if (WIFEXITED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has quit (exit code %d)\n",
+ pid, name?name:"", WEXITSTATUS(status))
+ )
+ else
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has quit", pid, name?name:"")
+ )
+
+ if (pid == starter_pluto_pid())
+ starter_pluto_sigchild(pid);
#ifdef IKEV2
- if (pid == starter_charon_pid())
- starter_charon_sigchild(pid);
+ if (pid == starter_charon_pid())
+ starter_charon_sigchild(pid);
#endif /* IKEV2 */
- }
- }
- break;
+ }
+ }
+ break;
case SIGPIPE:
- /** ignore **/
- break;
+ /** ignore **/
+ break;
case SIGALRM:
- _action_ |= FLAG_ACTION_START_PLUTO;
+ _action_ |= FLAG_ACTION_START_PLUTO;
#ifdef IKEV2
- _action_ |= FLAG_ACTION_START_CHARON;
+ _action_ |= FLAG_ACTION_START_CHARON;
#endif /* IKEV2 */
- break;
+ break;
case SIGHUP:
- _action_ |= FLAG_ACTION_UPDATE;
- break;
+ _action_ |= FLAG_ACTION_UPDATE;
+ break;
case SIGTERM:
case SIGQUIT:
case SIGINT:
_action_ |= FLAG_ACTION_QUIT;
- break;
+ break;
case SIGUSR1:
- _action_ |= FLAG_ACTION_RELOAD;
- _action_ |= FLAG_ACTION_UPDATE;
- break;
+ _action_ |= FLAG_ACTION_RELOAD;
+ _action_ |= FLAG_ACTION_UPDATE;
+ break;
default:
- plog("fsig(): unknown signal %d -- investigate", signal);
- break;
+ plog("fsig(): unknown signal %d -- investigate", signal);
+ break;
}
}
static void
usage(char *name)
{
- fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] "
- "[--debug|--debug-more|--debug-all]\n");
- exit(1);
+ fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] "
+ "[--debug|--debug-more|--debug-all]\n");
+ exit(1);
}
int main (int argc, char **argv)
{
- starter_config_t *cfg = NULL;
- starter_config_t *new_cfg;
- starter_conn_t *conn, *conn2;
- starter_ca_t *ca, *ca2;
+ starter_config_t *cfg = NULL;
+ starter_config_t *new_cfg;
+ starter_conn_t *conn, *conn2;
+ starter_ca_t *ca, *ca2;
- struct stat stb;
+ struct stat stb;
- char *err = NULL;
- int i;
- int id = 1;
- struct timeval tv;
- unsigned long auto_update = 0;
- time_t last_reload;
- bool no_fork = FALSE;
+ char *err = NULL;
+ int i;
+ int id = 1;
+ struct timeval tv;
+ unsigned long auto_update = 0;
+ time_t last_reload;
+ bool no_fork = FALSE;
- /* global variables defined in log.h */
- log_to_stderr = TRUE;
- base_debugging = DBG_NONE;
+ /* global variables defined in log.h */
+ log_to_stderr = TRUE;
+ base_debugging = DBG_NONE;
/* parse command line */
- for (i = 1; i < argc; i++)
- {
- if (streq(argv[i], "--debug"))
+ for (i = 1; i < argc; i++)
{
- base_debugging |= DBG_CONTROL;
+ if (streq(argv[i], "--debug"))
+ {
+ base_debugging |= DBG_CONTROL;
+ }
+ else if (streq(argv[i], "--debug-more"))
+ {
+ base_debugging |= DBG_CONTROLMORE;
+ }
+ else if (streq(argv[i], "--debug-all"))
+ {
+ base_debugging |= DBG_ALL;
+ }
+ else if (streq(argv[i], "--nofork"))
+ {
+ no_fork = TRUE;
+ }
+ else if (streq(argv[i], "--auto-update") && i+1 < argc)
+ {
+ auto_update = atoi(argv[++i]);
+ if (!auto_update)
+ usage(argv[0]);
+ }
+ else
+ {
+ usage(argv[0]);
+ }
}
- else if (streq(argv[i], "--debug-more"))
+
+ /* Init */
+ init_log("ipsec_starter");
+ cur_debugging = base_debugging;
+
+ signal(SIGHUP, fsig);
+ signal(SIGCHLD, fsig);
+ signal(SIGPIPE, fsig);
+ signal(SIGINT, fsig);
+ signal(SIGTERM, fsig);
+ signal(SIGQUIT, fsig);
+ signal(SIGALRM, fsig);
+ signal(SIGUSR1, fsig);
+
+ plog("Starting strongSwan IPsec %s [starter]...", ipsec_version_code());
+
+ /* verify that we can start */
+ if (getuid() != 0)
{
- base_debugging |= DBG_CONTROLMORE;
+ plog("permission denied (must be superuser)");
+ exit(1);
}
- else if (streq(argv[i], "--debug-all"))
+
+ if (stat(PLUTO_PID_FILE, &stb) == 0)
{
- base_debugging |= DBG_ALL;
+ plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE);
}
- else if (streq(argv[i], "--nofork"))
+ else
{
- no_fork = TRUE;
+ _action_ |= FLAG_ACTION_START_PLUTO;
}
- else if (streq(argv[i], "--auto-update") && i+1 < argc)
+#ifdef IKEV2
+ if (stat(CHARON_PID_FILE, &stb) == 0)
{
- auto_update = atoi(argv[++i]);
- if (!auto_update)
- usage(argv[0]);
+ plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE);
}
else
{
- usage(argv[0]);
+ _action_ |= FLAG_ACTION_START_CHARON;
}
- }
-
- /* Init */
- init_log("ipsec_starter");
- cur_debugging = base_debugging;
-
- signal(SIGHUP, fsig);
- signal(SIGCHLD, fsig);
- signal(SIGPIPE, fsig);
- signal(SIGINT, fsig);
- signal(SIGTERM, fsig);
- signal(SIGQUIT, fsig);
- signal(SIGALRM, fsig);
- signal(SIGUSR1, fsig);
-
-
- plog("Starting strongSwan IPsec %s [starter]...", ipsec_version_code());
-
- /* verify that we can start */
- if (getuid() != 0)
- {
- plog("permission denied (must be superuser)");
- exit(1);
- }
-
- if (stat(PLUTO_PID_FILE, &stb) == 0)
- {
- plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE);
- }
- else
- {
- _action_ |= FLAG_ACTION_START_PLUTO;
- }
-#ifdef IKEV2
- if (stat(CHARON_PID_FILE, &stb) == 0)
- {
- plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE);
- }
- else
- {
- _action_ |= FLAG_ACTION_START_CHARON;
- }
#endif /* IKEV2 */
- if (stat(DEV_RANDOM, &stb) != 0)
- {
- plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
- exit(1);
- }
-
- if (stat(DEV_URANDOM, &stb)!= 0)
- {
- plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
- exit(1);
- }
+ if (stat(DEV_RANDOM, &stb) != 0)
+ {
+ plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
+ exit(1);
+ }
- cfg = confread_load(CONFIG_FILE);
- if (!cfg)
- {
- plog("unable to start strongSwan -- errors in config");
- exit(1);
- }
+ if (stat(DEV_URANDOM, &stb)!= 0)
+ {
+ plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
+ exit(1);
+ }
- /* determine if we have a native netkey IPsec stack */
- if (!starter_netkey_init())
- {
- plog("nor netkey IPSec stack detected");
- exit(1);
- }
+ cfg = confread_load(CONFIG_FILE);
+ if (!cfg)
+ {
+ plog("unable to start strongSwan -- errors in config");
+ exit(1);
+ }
- last_reload = time(NULL);
+ /* determine if we have a native netkey IPsec stack */
+ if (!starter_netkey_init())
+ {
+ plog("nor netkey IPSec stack detected");
+ exit(1);
+ }
- if (stat(MY_PID_FILE, &stb) == 0)
- {
- plog("starter is already running (%s exists) -- no fork done", MY_PID_FILE);
- exit(0);
- }
+ last_reload = time(NULL);
- /* fork if we're not debugging stuff */
- if (!no_fork)
- {
- log_to_stderr = FALSE;
+ if (stat(MY_PID_FILE, &stb) == 0)
+ {
+ plog("starter is already running (%s exists) -- no fork done", MY_PID_FILE);
+ exit(0);
+ }
- switch (fork())
+ /* fork if we're not debugging stuff */
+ if (!no_fork)
{
- case 0:
- {
- int fnull = open("/dev/null", O_RDWR);
+ log_to_stderr = FALSE;
- if (fnull >= 0)
+ switch (fork())
{
- dup2(fnull, STDIN_FILENO);
- dup2(fnull, STDOUT_FILENO);
- dup2(fnull, STDERR_FILENO);
- close(fnull);
+ case 0:
+ {
+ int fnull = open("/dev/null", O_RDWR);
+
+ if (fnull >= 0)
+ {
+ dup2(fnull, STDIN_FILENO);
+ dup2(fnull, STDOUT_FILENO);
+ dup2(fnull, STDERR_FILENO);
+ close(fnull);
+ }
+ }
+ break;
+ case -1:
+ plog("can't fork: %s", strerror(errno));
+ break;
+ default:
+ exit(0);
}
- }
- break;
- case -1:
- plog("can't fork: %s", strerror(errno));
- break;
- default:
- exit(0);
- }
}
/* save pid file in /var/run/starter.pid */
{
- FILE *fd = fopen(MY_PID_FILE, "w");
+ FILE *fd = fopen(MY_PID_FILE, "w");
- if (fd)
- {
- fprintf(fd, "%u\n", getpid());
- fclose(fd);
- }
+ if (fd)
+ {
+ fprintf(fd, "%u\n", getpid());
+ fclose(fd);
+ }
}
for (;;)
{
- /*
- * Stop pluto/charon (if started) and exit
- */
- if (_action_ & FLAG_ACTION_QUIT)
- {
- if (starter_pluto_pid())
- starter_stop_pluto();
+ /*
+ * Stop pluto/charon (if started) and exit
+ */
+ if (_action_ & FLAG_ACTION_QUIT)
+ {
+ if (starter_pluto_pid())
+ starter_stop_pluto();
#ifdef IKEV2
- if (starter_charon_pid())
- starter_stop_charon();
-#endif IKEV2
- starter_netkey_cleanup();
- confread_free(cfg);
- unlink(MY_PID_FILE);
- unlink(INFO_FILE);
+ if (starter_charon_pid())
+ starter_stop_charon();
+#endif /* IKEV2 */
+ starter_netkey_cleanup();
+ confread_free(cfg);
+ unlink(MY_PID_FILE);
+ unlink(INFO_FILE);
#ifdef LEAK_DETECTIVE
- report_leaks();
+ report_leaks();
#endif /* LEAK_DETECTIVE */
- close_log();
- plog("ipsec starter stopped");
- exit(0);
- }
+ close_log();
+ plog("ipsec starter stopped");
+ exit(0);
+ }
- /*
- * Delete all connections. Will be added below
- */
- if (_action_ & FLAG_ACTION_RELOAD)
- {
- if (starter_pluto_pid())
- {
- for (conn = cfg->conn_first; conn; conn = conn->next)
+ /*
+ * Delete all connections. Will be added below
+ */
+ if (_action_ & FLAG_ACTION_RELOAD)
{
- if (conn->state == STATE_ADDED)
- {
- starter_whack_del_conn(conn);
+ if (starter_pluto_pid())
+ {
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
#ifdef IKEV2
- starter_stroke_del_conn(conn);
+ if (conn->keyexchange == KEY_EXCHANGE_IKEV2)
+ {
+ starter_stroke_del_conn(conn);
+ }
#endif /* IKEV2 */
- conn->state = STATE_TO_ADD;
- }
- }
- for (ca = cfg->ca_first; ca; ca = ca->next)
- {
- if (ca->state == STATE_ADDED)
- {
- starter_whack_del_ca(ca);
- ca->state = STATE_TO_ADD;
- }
- }
- }
- _action_ &= ~FLAG_ACTION_RELOAD;
- }
-
- /*
- * Update configuration
- */
- if (_action_ & FLAG_ACTION_UPDATE)
- {
- err = NULL;
- DBG(DBG_CONTROL,
- DBG_log("Reloading config...")
- )
- new_cfg = confread_load(CONFIG_FILE);
-
- if (new_cfg)
- {
- /* Switch to new config. New conn will be loaded below */
- if (!starter_cmp_defaultroute(&new_cfg->defaultroute
- , &cfg->defaultroute))
- {
- _action_ |= FLAG_ACTION_LISTEN;
+ else
+ {
+ starter_whack_del_conn(conn);
+ }
+ conn->state = STATE_TO_ADD;
+ }
+ }
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ {
+ starter_whack_del_ca(ca);
+ ca->state = STATE_TO_ADD;
+ }
+ }
+ }
+ _action_ &= ~FLAG_ACTION_RELOAD;
}
- if (!starter_cmp_pluto(cfg, new_cfg))
- {
- plog("Pluto has changed");
- if (starter_pluto_pid())
- starter_stop_pluto();
- _action_ &= ~FLAG_ACTION_LISTEN;
- _action_ |= FLAG_ACTION_START_PLUTO;
- }
- else
+ /*
+ * Update configuration
+ */
+ if (_action_ & FLAG_ACTION_UPDATE)
{
- /* Only reload conn and ca sections if pluto is not killed */
+ err = NULL;
+ DBG(DBG_CONTROL,
+ DBG_log("Reloading config...")
+ )
+ new_cfg = confread_load(CONFIG_FILE);
- /* Look for new connections that are already loaded */
- for (conn = cfg->conn_first; conn; conn = conn->next)
- {
- if (conn->state == STATE_ADDED)
+ if (new_cfg)
{
- for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next)
- {
- if (conn2->state == STATE_TO_ADD
- && starter_cmp_conn(conn, conn2))
+ /* Switch to new config. New conn will be loaded below */
+ if (!starter_cmp_defaultroute(&new_cfg->defaultroute
+ , &cfg->defaultroute))
{
- conn->state = STATE_REPLACED;
- conn2->state = STATE_ADDED;
- conn2->id = conn->id;
- break;
+ _action_ |= FLAG_ACTION_LISTEN;
}
- }
- }
- }
- /* Remove conn sections that have become unused */
- for (conn = cfg->conn_first; conn; conn = conn->next)
- {
- if (conn->state == STATE_ADDED)
- starter_whack_del_conn(conn);
+ if (!starter_cmp_pluto(cfg, new_cfg))
+ {
+ plog("Pluto has changed");
+ if (starter_pluto_pid())
+ starter_stop_pluto();
+ _action_ &= ~FLAG_ACTION_LISTEN;
+ _action_ |= FLAG_ACTION_START_PLUTO;
+ }
+ else
+ {
+ /* Only reload conn and ca sections if pluto is not killed */
+
+ /* Look for new connections that are already loaded */
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
+ for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next)
+ {
+ if (conn2->state == STATE_TO_ADD
+ && starter_cmp_conn(conn, conn2))
+ {
+ conn->state = STATE_REPLACED;
+ conn2->state = STATE_ADDED;
+ conn2->id = conn->id;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Remove conn sections that have become unused */
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
#ifdef IKEV2
- starter_stroke_del_conn(conn);
+ if (conn->keyexchange == KEY_EXCHANGE_IKEV2)
+ {
+ starter_stroke_del_conn(conn);
+ }
+ else
#endif /* IKEV2 */
- }
+ {
+ starter_whack_del_conn(conn);
+ }
+ }
+ }
+
+ /* Look for new ca sections that are already loaded */
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ {
+ for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next)
+ {
+ if (ca2->state == STATE_TO_ADD
+ && starter_cmp_ca(ca, ca2))
+ {
+ ca->state = STATE_REPLACED;
+ ca2->state = STATE_ADDED;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Remove ca sections that have become unused */
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ starter_whack_del_ca(ca);
+ }
+ }
+ confread_free(cfg);
+ cfg = new_cfg;
+ }
+ else
+ {
+ plog("can't reload config file: %s -- keeping old one");
+ }
+ _action_ &= ~FLAG_ACTION_UPDATE;
+ last_reload = time(NULL);
+ }
- /* Look for new ca sections that are already loaded */
- for (ca = cfg->ca_first; ca; ca = ca->next)
- {
- if (ca->state == STATE_ADDED)
+ /*
+ * Start pluto
+ */
+ if (_action_ & FLAG_ACTION_START_PLUTO)
+ {
+ if (starter_pluto_pid() == 0)
{
- for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next)
- {
- if (ca2->state == STATE_TO_ADD
- && starter_cmp_ca(ca, ca2))
+ DBG(DBG_CONTROL,
+ DBG_log("Attempting to start pluto...")
+ )
+
+ if (starter_start_pluto(cfg, no_fork) == 0)
{
- ca->state = STATE_REPLACED;
- ca2->state = STATE_ADDED;
- break;
+ starter_whack_listen();
+ }
+ else
+ {
+ /* schedule next try */
+ alarm(PLUTO_RESTART_DELAY);
}
- }
}
- }
-
- /* Remove ca sections that have become unused */
- for (ca = cfg->ca_first; ca; ca = ca->next)
- {
- if (ca->state == STATE_ADDED)
- starter_whack_del_ca(ca);
- }
- }
- confread_free(cfg);
- cfg = new_cfg;
- }
- else
- {
- plog("can't reload config file: %s -- keeping old one");
- }
- _action_ &= ~FLAG_ACTION_UPDATE;
- last_reload = time(NULL);
- }
+ _action_ &= ~FLAG_ACTION_START_PLUTO;
- /*
- * Start pluto
- */
- if (_action_ & FLAG_ACTION_START_PLUTO)
- {
- if (starter_pluto_pid() == 0)
- {
- DBG(DBG_CONTROL,
- DBG_log("Attempting to start pluto...")
- )
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ ca->state = STATE_TO_ADD;
+ }
- if (starter_start_pluto(cfg, no_fork) == 0)
- {
- starter_whack_listen();
- }
- else
- {
- /* schedule next try */
- alarm(PLUTO_RESTART_DELAY);
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ conn->state = STATE_TO_ADD;
+ }
}
- }
- _action_ &= ~FLAG_ACTION_START_PLUTO;
-
- for (ca = cfg->ca_first; ca; ca = ca->next)
- {
- if (ca->state == STATE_ADDED)
- ca->state = STATE_TO_ADD;
- }
-
- for (conn = cfg->conn_first; conn; conn = conn->next)
- {
- if (conn->state == STATE_ADDED)
- conn->state = STATE_TO_ADD;
- }
- }
#ifdef IKEV2
- /*
- * Start charon
- */
- if (_action_ & FLAG_ACTION_START_CHARON)
- {
- if (starter_charon_pid() == 0)
+ /*
+ * Start charon
+ */
+ if (_action_ & FLAG_ACTION_START_CHARON)
{
- DBG(DBG_CONTROL,
- DBG_log("Attempting to start charon...")
- )
- if (starter_start_charon(cfg, no_fork) != 0)
+ if (starter_charon_pid() == 0)
{
- /* schedule next try */
- alarm(PLUTO_RESTART_DELAY);
+ DBG(DBG_CONTROL,
+ DBG_log("Attempting to start charon...")
+ )
+ if (starter_start_charon(cfg, no_fork) != 0)
+ {
+ /* schedule next try */
+ alarm(PLUTO_RESTART_DELAY);
+ }
}
+ _action_ &= ~FLAG_ACTION_START_CHARON;
}
- _action_ &= ~FLAG_ACTION_START_CHARON;
- }
#endif /* IKEV2 */
- /*
- * Tell pluto to reread its interfaces
- */
- if (_action_ & FLAG_ACTION_LISTEN)
- {
- starter_whack_listen();
- _action_ &= ~FLAG_ACTION_LISTEN;
- }
-
- /*
- * Add stale conn and ca sections
- */
- if (starter_pluto_pid() != 0)
- {
- for (ca = cfg->ca_first; ca; ca = ca->next)
- {
- if (ca->state == STATE_TO_ADD)
+ /*
+ * Tell pluto to reread its interfaces
+ */
+ if (_action_ & FLAG_ACTION_LISTEN)
{
- starter_whack_add_ca(ca);
- ca->state = STATE_ADDED;
+ starter_whack_listen();
+ _action_ &= ~FLAG_ACTION_LISTEN;
}
- }
- for (conn = cfg->conn_first; conn; conn = conn->next)
- {
- if (conn->state == STATE_TO_ADD)
+ /*
+ * Add stale conn and ca sections
+ */
+ if (starter_pluto_pid() != 0)
{
- if (conn->id == 0)
- {
- /* affect new unique id */
- conn->id = id++;
- }
- starter_whack_add_conn(conn);
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_TO_ADD)
+ {
+ starter_whack_add_ca(ca);
+ ca->state = STATE_ADDED;
+ }
+ }
+
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_TO_ADD)
+ {
+ if (conn->id == 0)
+ {
+ /* affect new unique id */
+ conn->id = id++;
+ }
#ifdef IKEV2
- starter_stroke_add_conn(conn);
+ if (conn->keyexchange == KEY_EXCHANGE_IKEV2)
+ {
+ starter_stroke_add_conn(conn);
+ }
+ else
#endif /* IKEV2 */
- conn->state = STATE_ADDED;
- if (conn->startup == STARTUP_START)
- {
+ {
+ starter_whack_add_conn(conn);
+ }
+ conn->state = STATE_ADDED;
+
+ if (conn->startup == STARTUP_START)
+ {
#ifdef IKEV2
- if (conn->keyexchange == 2)
- {
- starter_stroke_initiate_conn(conn);
- }
- else
+ if (conn->keyexchange == KEY_EXCHANGE_IKEV2)
+ {
+ starter_stroke_initiate_conn(conn);
+ }
+ else
#endif /* IKEV2 */
- {
- starter_whack_initiate_conn(conn);
- }
- }
- else if (conn->startup == STARTUP_ROUTE)
- {
+ {
+ starter_whack_initiate_conn(conn);
+ }
+ }
+ else if (conn->startup == STARTUP_ROUTE)
+ {
#ifdef IKEV2
- if (conn->keyexchange == 2)
- {
- starter_stroke_route_conn(conn);
- }
- else
+ if (conn->keyexchange == KEY_EXCHANGE_IKEV2)
+ {
+ starter_stroke_route_conn(conn);
+ }
+ else
#endif /* IKEV2 */
- {
- starter_whack_route_conn(conn);
+ {
+ starter_whack_route_conn(conn);
+ }
+ }
+ }
}
- }
}
- }
- }
- /*
- * If auto_update activated, when to stop select
- */
- if (auto_update)
- {
- time_t now = time(NULL);
- tv.tv_sec = (now < last_reload + auto_update)
- ? (last_reload + auto_update-now) : 0;
- tv.tv_usec = 0;
- }
+ /*
+ * If auto_update activated, when to stop select
+ */
+ if (auto_update)
+ {
+ time_t now = time(NULL);
- /*
- * Wait for something to happen
- */
- if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0)
- {
- /* timeout -> auto_update */
- _action_ |= FLAG_ACTION_UPDATE;
+ tv.tv_sec = (now < last_reload + auto_update)
+ ? (last_reload + auto_update-now) : 0;
+ tv.tv_usec = 0;
+ }
+
+ /*
+ * Wait for something to happen
+ */
+ if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0)
+ {
+ /* timeout -> auto_update */
+ _action_ |= FLAG_ACTION_UPDATE;
+ }
}
- }
- return 0;
+ return 0;
}
diff --git a/testing/do-tests b/testing/do-tests
index ceddd72d8..c4c624ea9 100755
--- a/testing/do-tests
+++ b/testing/do-tests
@@ -374,6 +374,9 @@ do
eval HOSTLOGIN=root@\$ip_${host}
ssh $HOSTLOGIN grep pluto /var/log/auth.log \
> $TESTRESULTDIR/${host}.auth.log
+ echo >> $TESTRESULTDIR/${host}.auth.log
+ ssh $HOSTLOGIN grep charon /var/log/auth.log \
+ >> $TESTRESULTDIR/${host}.auth.log
done
diff --git a/testing/scripts/build-umlrootfs b/testing/scripts/build-umlrootfs
index ba103838f..c2726cfc9 100755
--- a/testing/scripts/build-umlrootfs
+++ b/testing/scripts/build-umlrootfs
@@ -128,6 +128,7 @@ echo "export USERCOMPILE=\'-DRANDOM_DEVICE=\\\"/dev/urandom\\\"\'" >> $INSTALLSH
echo "cd /root/${STRONGSWANVERSION}" >> $INSTALLSHELL
echo "make programs" >> $INSTALLSHELL
echo "make install" >> $INSTALLSHELL
+echo "ldconfig" >> $INSTALLSHELL
cecho-n " * Compiling $STRONGSWANVERSION within the root file system as chroot.."
chroot $LOOPDIR /bin/bash /install.sh >> $LOGFILE 2>&1
diff --git a/testing/tests/ikev2-net2net/description.txt b/testing/tests/ikev2-net2net/description.txt
new file mode 100644
index 000000000..7eea9192f
--- /dev/null
+++ b/testing/tests/ikev2-net2net/description.txt
@@ -0,0 +1,6 @@
+A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up.
+The authentication is based on <b>X.509 certificates</b>. Upon the successful
+establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic.
+In order to test both tunnel and firewall, client <b>alice</b> behind gateway <b>moon</b>
+pings client <b>bob</b> located behind gateway <b>sun</b>.
diff --git a/testing/tests/ikev2-net2net/evaltest.dat b/testing/tests/ikev2-net2net/evaltest.dat
new file mode 100644
index 000000000..bb4eac44e
--- /dev/null
+++ b/testing/tests/ikev2-net2net/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec statusall::net-net.*IKE_SA_ESTABLISHED::YES
+sun::ipsec statusall::net-net.*IKE_SA_ESTABLISHED::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.conf
new file mode 100644
index 000000000..9a95d4040
--- /dev/null
+++ b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,13 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+conn net-net
+ left=192.168.0.1
+ leftcert=moonCert.pem
+ leftsubnet=10.1.0.0/16
+ right=192.168.0.2
+ rightcert=sunCert.pem
+ rightsubnet=10.2.0.0/16
+ keyexchange=ikev2
+ auto=add
diff --git a/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.d/certs/sunCert.pem b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.d/certs/sunCert.pem
new file mode 100644
index 000000000..e7825e3db
--- /dev/null
+++ b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.d/certs/sunCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIECzCCAvOgAwIBAgIBAjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTU1M1oXDTA5MDkwOTExMTU1M1owRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN1bi5z
+dHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOQ8
+foB9h5BZ92gA5JkQTJNuoF6FAzoq91Gh7To27/g74p01+SUnsSaBfPmNfGp4avdS
+Ewy2dWMA/7uj0Dbe8MEKssNztp0JQubp2s7n8mrrQLGsqB6YAS09l75XDjS3yqTC
+AtH1kD4zAl/j/AyeQBuLR4CyJEmC/rqD3/a+pr42CaljuFBgBRpCTUpU4mlslZSe
+zv9wu61PwTFxb8VDlBHUd/lwkXThKgU3uEhWRxLahpSldEGmiTTmx30k/XbOMF2n
+HObEHt5EY9uWRGGbj81ZRWiNk0dNtbpneUHv/NvdWLc591M8cEGEQdWW2XTVbL2G
+N67q8hdzGgIvb7QJPMcCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQD
+AgOoMB0GA1UdDgQWBBQ9xLkyCBbyQmRet0vvV1Fg6z5q2DBtBgNVHSMEZjBkgBRd
+p91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoT
+EExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIB
+ADAdBgNVHREEFjAUghJzdW4uc3Ryb25nc3dhbi5vcmcwOQYDVR0fBDIwMDAuoCyg
+KoYoaHR0cDovL2NybC5zdHJvbmdzd2FuLm9yZy9zdHJvbmdzd2FuLmNybDANBgkq
+hkiG9w0BAQQFAAOCAQEAGQQroiAa0SwwhJprGd7OM+rfBJAGbsa3DPzFCfHX1R7i
+ZyDs9aph1DK+IgUa377Ev1U7oB0EldpmOoJJugCjtNLfpW3t1RXBERL/QfpO2+VP
+Wt3SfZ0Oq48jiqB1MVLMZRPCICZEQjT4sJ3HYs5ZuucuvoxeMx3rQ4HxUtHtMD3S
+5JNMwFFiOXAjyIyrTlb7YuRJTT5hE+Rms8GUQ5Xnt7zKZ7yfoSLFzy0/cLFPdQvE
+JA7w8crODCZpDgEKVHVyUWuyt1O46N3ydUfDcnKJoQ9HWHm3xCbDex5MHTnvm1lk
+Stx71CGM7TE6VPy028UlrSw0JqEwCVwstei2cMzwgA==
+-----END CERTIFICATE-----
diff --git a/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.conf b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.conf
new file mode 100644
index 000000000..b2c2b71ec
--- /dev/null
+++ b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,13 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+conn net-net
+ left=192.168.0.2
+ leftcert=sunCert.pem
+ leftsubnet=10.2.0.0/16
+ right=192.168.0.1
+ rightcert=moonCert.pem
+ rightsubnet=10.1.0.0/16
+ keyexchange=ikev2
+ auto=add
diff --git a/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.d/certs/moonCert.pem b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.d/certs/moonCert.pem
new file mode 100644
index 000000000..d8fbfa1c9
--- /dev/null
+++ b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.d/certs/moonCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDTCCAvWgAwIBAgIBAzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTcyNVoXDTA5MDkwOTExMTcyNVowRjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAMTE21vb24u
+c3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv
+ri4QmsCnG0N7bxqeUZTQhcmZ/iyN4RsmHwFsiOc06xpnZ7Fbx9gzi/OswU6KGL+F
+f9PfvOY36bDTZU8V2QaL30RQUXz3JlG+jUyP9zjqlhsvVYS/cImvqgo3uUkQ0YCD
+v2SafTlaQfBOaPFElNEP/H2YSiyB6X80IcHsOMYpskVqPY8785FehjF+pxuyRCK+
+9HXmd+iWdnC09u4qgKRa3L0IamU3q1/BK/afkHK2IAIN4YgM7GzepHVD0f7Exf9U
+esJEeh4hDZwSjcMzdybrY9XBxzGqLGPOF128jr+5weUZiBW+RzeBw/gsK1nSPeuX
+Od2lPJjTGj+6V3YK6qibAgMBAAGjggEFMIIBATAJBgNVHRMEAjAAMAsGA1UdDwQE
+AwIDqDAdBgNVHQ4EFgQU5eQQh2wqxL6thUlCpt52WDA6n8EwbQYDVR0jBGYwZIAU
+XafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQK
+ExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GC
+AQAwHgYDVR0RBBcwFYITbW9vbi5zdHJvbmdzd2FuLm9yZzA5BgNVHR8EMjAwMC6g
+LKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0G
+CSqGSIb3DQEBBAUAA4IBAQAvLykhZnqldrsMcbYB36WzWKk+hOihr5dU3fv8Z4ec
+tsa3gzxXSefDCxGoezVJ4QXdpdNxxFn31A+r1gxKyGI5JL6EyWz6Y462zp9lE7nW
+EIC4ldJwxAXqzDEMcJphO29hApyU9TWsWDa4kL5AKtLFLwH3/Uv/jAzAy+qXIO8h
+wLtB+wcmhSo8OFY9kX/cyhht7eb7yD/r2e3wVBOCRk7jePe4yWhN8NJAKwfrEd1K
+iGq15ymdmeomhplHRsLZwA2VsCspUNZ/eXjG21s3nEoxcCOcQUz3Q7q4ZgBTZoCW
+kAc6FQ5zxoZrmzNWFqzb06jmUVlt7baGtdjT7rEt+dcp
+-----END CERTIFICATE-----
diff --git a/testing/tests/ikev2-net2net/posttest.dat b/testing/tests/ikev2-net2net/posttest.dat
new file mode 100644
index 000000000..63c76ec65
--- /dev/null
+++ b/testing/tests/ikev2-net2net/posttest.dat
@@ -0,0 +1,4 @@
+moon::ipsec stop
+sun::ipsec stop
+moon::rm /etc/ipsec.d/certs/*
+sun::rm /etc/ipsec.d/certs/*
diff --git a/testing/tests/ikev2-net2net/pretest.dat b/testing/tests/ikev2-net2net/pretest.dat
new file mode 100644
index 000000000..33f838851
--- /dev/null
+++ b/testing/tests/ikev2-net2net/pretest.dat
@@ -0,0 +1,7 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+sun::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::ipsec start
+sun::ipsec start
+moon::sleep 1
+moon::ipsec up net-net
+moon::sleep 1
diff --git a/testing/tests/ikev2-net2net/test.conf b/testing/tests/ikev2-net2net/test.conf
new file mode 100644
index 000000000..d9a61590f
--- /dev/null
+++ b/testing/tests/ikev2-net2net/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"