From 918094fde55fa0dbfd59a5f88d576efb513a88db Mon Sep 17 00:00:00 2001
From: Yves-Alexis Perez <corsac@debian.org>
Date: Wed, 2 Jan 2019 10:45:36 +0100
Subject: New upstream version 5.7.2

---
 src/libstrongswan/credentials/auth_cfg.c           |   1 +
 src/libstrongswan/credentials/builder.c            |   1 +
 src/libstrongswan/credentials/builder.h            |   2 +
 src/libstrongswan/credentials/keys/private_key.h   |  13 +
 src/libstrongswan/credentials/keys/public_key.c    |   2 +-
 .../credentials/keys/signature_params.c            |  50 +-
 .../credentials/keys/signature_params.h            |  19 +-
 src/libstrongswan/crypto/mac.h                     |   4 +-
 .../crypto/proposal/proposal_keywords_static.c     |  24 +-
 .../crypto/proposal/proposal_keywords_static.h     |   2 +-
 .../plugins/agent/agent_private_key.c              | 133 ++-
 src/libstrongswan/plugins/botan/Makefile.am        |   4 +-
 src/libstrongswan/plugins/botan/Makefile.in        |  13 +-
 src/libstrongswan/plugins/botan/botan_aead.c       | 388 +++++++++
 src/libstrongswan/plugins/botan/botan_aead.h       |  50 ++
 src/libstrongswan/plugins/botan/botan_crypter.c    |   6 +
 .../plugins/botan/botan_ec_public_key.c            |  19 +-
 .../plugins/botan/botan_ed_private_key.c           | 279 +++++++
 .../plugins/botan/botan_ed_private_key.h           |  63 ++
 .../plugins/botan/botan_ed_public_key.c            | 202 +++++
 .../plugins/botan/botan_ed_public_key.h            |  51 ++
 src/libstrongswan/plugins/botan/botan_gcm.c        | 333 --------
 src/libstrongswan/plugins/botan/botan_gcm.h        |  47 --
 src/libstrongswan/plugins/botan/botan_plugin.c     |  77 +-
 .../plugins/botan/botan_rsa_private_key.c          |  24 +-
 .../plugins/botan/botan_rsa_public_key.c           |  66 +-
 src/libstrongswan/plugins/botan/botan_util.c       |  35 +
 src/libstrongswan/plugins/botan/botan_util.h       |  12 +
 src/libstrongswan/plugins/botan/botan_util_keys.c  |  38 +-
 .../plugins/curve25519/curve25519_public_key.c     | 110 ++-
 src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c   |   4 +
 .../plugins/gcrypt/gcrypt_rsa_private_key.c        |   6 +-
 .../plugins/gcrypt/gcrypt_rsa_public_key.c         |   6 +-
 .../plugins/gmp/gmp_rsa_private_key.c              |   6 +-
 src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c |   7 +-
 src/libstrongswan/plugins/mysql/mysql_database.c   |  10 +-
 src/libstrongswan/plugins/openssl/Makefile.am      |   5 +-
 src/libstrongswan/plugins/openssl/Makefile.in      |  11 +-
 src/libstrongswan/plugins/openssl/openssl_crl.c    |  21 +-
 .../plugins/openssl/openssl_ed_private_key.c       | 356 ++++++++
 .../plugins/openssl/openssl_ed_private_key.h       |  58 ++
 .../plugins/openssl/openssl_ed_public_key.c        | 304 +++++++
 .../plugins/openssl/openssl_ed_public_key.h        |  38 +
 src/libstrongswan/plugins/openssl/openssl_plugin.c |  53 +-
 src/libstrongswan/plugins/openssl/openssl_rng.c    |  11 +-
 .../plugins/openssl/openssl_rsa_private_key.c      |   7 +-
 .../plugins/openssl/openssl_rsa_public_key.c       |   7 +-
 src/libstrongswan/plugins/openssl/openssl_util.c   |   8 +-
 src/libstrongswan/plugins/openssl/openssl_util.h   |   4 +-
 src/libstrongswan/plugins/openssl/openssl_x509.c   |  14 +-
 .../plugins/openssl/openssl_x_diffie_hellman.c     | 256 ++++++
 .../plugins/openssl/openssl_x_diffie_hellman.h     |  37 +
 src/libstrongswan/plugins/sshkey/sshkey_builder.c  |  35 +-
 src/libstrongswan/plugins/sshkey/sshkey_encoder.c  |  38 +-
 src/libstrongswan/plugins/test_vectors/Makefile.am |   1 +
 src/libstrongswan/plugins/test_vectors/Makefile.in |   7 +-
 .../plugins/test_vectors/test_vectors.h            |   2 +
 .../test_vectors/test_vectors/chacha20poly1305.c   |  40 +-
 .../plugins/test_vectors/test_vectors/curve25519.c |   2 +-
 .../plugins/test_vectors/test_vectors/curve448.c   |  43 +
 src/libstrongswan/settings/settings_lexer.c        | 898 +++++++++++++--------
 src/libstrongswan/settings/settings_lexer.l        |   5 +
 src/libstrongswan/tests/Makefile.am                |   1 +
 src/libstrongswan/tests/Makefile.in                |  19 +
 src/libstrongswan/tests/suites/test_ed25519.c      |  84 +-
 src/libstrongswan/tests/suites/test_ed448.c        | 654 +++++++++++++++
 src/libstrongswan/tests/suites/test_rsa.c          |   2 +-
 .../tests/suites/test_signature_params.c           |  61 +-
 src/libstrongswan/tests/tests.h                    |   1 +
 src/libstrongswan/utils/chunk.h                    |   2 +-
 src/libstrongswan/utils/leak_detective.c           |  42 +-
 71 files changed, 4238 insertions(+), 996 deletions(-)
 create mode 100644 src/libstrongswan/plugins/botan/botan_aead.c
 create mode 100644 src/libstrongswan/plugins/botan/botan_aead.h
 create mode 100644 src/libstrongswan/plugins/botan/botan_ed_private_key.c
 create mode 100644 src/libstrongswan/plugins/botan/botan_ed_private_key.h
 create mode 100644 src/libstrongswan/plugins/botan/botan_ed_public_key.c
 create mode 100644 src/libstrongswan/plugins/botan/botan_ed_public_key.h
 delete mode 100644 src/libstrongswan/plugins/botan/botan_gcm.c
 delete mode 100644 src/libstrongswan/plugins/botan/botan_gcm.h
 create mode 100644 src/libstrongswan/plugins/openssl/openssl_ed_private_key.c
 create mode 100644 src/libstrongswan/plugins/openssl/openssl_ed_private_key.h
 create mode 100644 src/libstrongswan/plugins/openssl/openssl_ed_public_key.c
 create mode 100644 src/libstrongswan/plugins/openssl/openssl_ed_public_key.h
 create mode 100644 src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c
 create mode 100644 src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h
 create mode 100644 src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c
 create mode 100644 src/libstrongswan/tests/suites/test_ed448.c

(limited to 'src/libstrongswan')

diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
index 278c67405..b04627e63 100644
--- a/src/libstrongswan/credentials/auth_cfg.c
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -551,6 +551,7 @@ static signature_params_t *create_rsa_pss_constraint(char *token)
 			.scheme = SIGN_RSA_EMSA_PSS,
 			.params = &pss,
 		};
+		rsa_pss_params_set_salt_len(&pss, 0);
 		params = signature_params_clone(&pss_params);
 	}
 	return params;
diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c
index 0239ee17e..61dfbbcad 100644
--- a/src/libstrongswan/credentials/builder.c
+++ b/src/libstrongswan/credentials/builder.c
@@ -73,6 +73,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
 	"BUILD_SAFE_PRIMES",
 	"BUILD_SHARES",
 	"BUILD_THRESHOLD",
+	"BUILD_EDDSA_PUB",
 	"BUILD_EDDSA_PRIV_ASN1_DER",
 	"BUILD_END",
 );
diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h
index 7928ef487..b283bd166 100644
--- a/src/libstrongswan/credentials/builder.h
+++ b/src/libstrongswan/credentials/builder.h
@@ -156,6 +156,8 @@ enum builder_part_t {
 	BUILD_SHARES,
 	/** minimum number of participating private key shares */
 	BUILD_THRESHOLD,
+	/** EdDSA public key blob */
+	BUILD_EDDSA_PUB,
 	/** DER encoded ASN.1 EdDSA private key */
 	BUILD_EDDSA_PRIV_ASN1_DER,
 	/** end of variable argument builder list */
diff --git a/src/libstrongswan/credentials/keys/private_key.h b/src/libstrongswan/credentials/keys/private_key.h
index d7cfdd74d..5cf8641ad 100644
--- a/src/libstrongswan/credentials/keys/private_key.h
+++ b/src/libstrongswan/credentials/keys/private_key.h
@@ -39,6 +39,19 @@ struct private_key_t {
 	 */
 	key_type_t (*get_type)(private_key_t *this);
 
+	/**
+	 * Get signature schemes supported by this key.
+	 *
+	 * This is useful for keys that only support certain hash algorithms or
+	 * require specific parameters for RSA/PSS signatures.
+	 *
+	 * @note Implementing this method is optional. If multiple schemes are
+	 * returned, they should be ordered by decreasing preference.
+	 *
+	 * @return			enumerator over signature_params_t*
+	 */
+	enumerator_t *(*supported_signature_schemes)(private_key_t *this);
+
 	/**
 	 * Create a signature over a chunk of data.
 	 *
diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c
index 89fa9b348..3ef6981f6 100644
--- a/src/libstrongswan/credentials/keys/public_key.c
+++ b/src/libstrongswan/credentials/keys/public_key.c
@@ -250,7 +250,7 @@ int signature_scheme_to_oid(signature_scheme_t scheme)
 #define PSS_PARAMS(bits) static rsa_pss_params_t pss_params_sha##bits = { \
 	.hash = HASH_SHA##bits, \
 	.mgf1_hash = HASH_SHA##bits, \
-	.salt_len = RSA_PSS_SALT_LEN_DEFAULT, \
+	.salt_len = HASH_SIZE_SHA##bits, \
 }
 
 PSS_PARAMS(256);
diff --git a/src/libstrongswan/credentials/keys/signature_params.c b/src/libstrongswan/credentials/keys/signature_params.c
index 8f42fb940..d89bd2c96 100644
--- a/src/libstrongswan/credentials/keys/signature_params.c
+++ b/src/libstrongswan/credentials/keys/signature_params.c
@@ -18,22 +18,43 @@
 #include <asn1/oid.h>
 #include <asn1/asn1_parser.h>
 
-/**
- * Determine the salt length in case it is not configured
+/*
+ * Described in header
  */
-static ssize_t rsa_pss_salt_length(rsa_pss_params_t *pss)
+bool rsa_pss_params_set_salt_len(rsa_pss_params_t *params, size_t modbits)
 {
-	ssize_t salt_len = pss->salt_len;
+	size_t hash_len;
 
-	if (salt_len <= RSA_PSS_SALT_LEN_DEFAULT)
+	if (params->salt_len < 0)
 	{
-		salt_len = hasher_hash_size(pss->hash);
-		if (!salt_len)
+		hash_len = hasher_hash_size(params->hash);
+		if (!hash_len)
+		{
+			return FALSE;
+		}
+
+		switch (params->salt_len)
 		{
-			return -1;
+			case RSA_PSS_SALT_LEN_DEFAULT:
+				params->salt_len = hash_len;
+				break;
+			case RSA_PSS_SALT_LEN_MAX:
+				if (modbits)
+				{
+					/* emBits = modBits - 1 */
+					modbits -= 1;
+					/* emLen = ceil(emBits/8) */
+					modbits = (modbits+7) / BITS_PER_BYTE;
+					/* account for 0x01 separator in DB, 0xbc trailing byte */
+					params->salt_len = max(0, (ssize_t)(modbits - hash_len - 2));
+					break;
+				}
+				return FALSE;
+			default:
+				return FALSE;
 		}
 	}
-	return salt_len;
+	return TRUE;
 }
 
 /**
@@ -68,8 +89,7 @@ static bool compare_params(signature_params_t *a, signature_params_t *b,
 
 				return pss_a->hash == pss_b->hash &&
 					   pss_a->mgf1_hash == pss_b->mgf1_hash &&
-					   (!strict ||
-						rsa_pss_salt_length(pss_a) == rsa_pss_salt_length(pss_b));
+					   (!strict || pss_a->salt_len == pss_b->salt_len);
 			}
 			default:
 				break;
@@ -328,7 +348,6 @@ end:
 bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1)
 {
 	chunk_t hash = chunk_empty, mgf = chunk_empty, slen = chunk_empty;
-	ssize_t salt_len;
 	int alg;
 
 	if (params->hash != HASH_SHA1)
@@ -351,16 +370,15 @@ bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1)
 		mgf = asn1_algorithmIdentifier_params(OID_MGF1,
 											  asn1_algorithmIdentifier(alg));
 	}
-	salt_len = rsa_pss_salt_length(params);
-	if (salt_len < 0)
+	if (params->salt_len < 0)
 	{
 		chunk_free(&hash);
 		chunk_free(&mgf);
 		return FALSE;
 	}
-	else if (salt_len != HASH_SIZE_SHA1)
+	else if (params->salt_len != HASH_SIZE_SHA1)
 	{
-		slen = asn1_integer("m", asn1_integer_from_uint64(salt_len));
+		slen = asn1_integer("m", asn1_integer_from_uint64(params->salt_len));
 	}
 	*asn1 = asn1_wrap(ASN1_SEQUENCE, "mmm",
 				hash.len ? asn1_wrap(ASN1_CONTEXT_C_0, "m", hash) : chunk_empty,
diff --git a/src/libstrongswan/credentials/keys/signature_params.h b/src/libstrongswan/credentials/keys/signature_params.h
index 6934c5e88..b4169a829 100644
--- a/src/libstrongswan/credentials/keys/signature_params.h
+++ b/src/libstrongswan/credentials/keys/signature_params.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Tobias Brunner
+ * Copyright (C) 2017-2018 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -100,11 +100,15 @@ struct rsa_pss_params_t {
 	hash_algorithm_t hash;
 	/** Hash for the MGF1 function */
 	hash_algorithm_t mgf1_hash;
-	/** Salt length, use RSA_PSS_SALT_LEN_DEFAULT for length equal to hash */
+	/** Salt length, use the constants below for special lengths resolved
+	 * via rsa_pss_params_set_salt_len() */
 	ssize_t salt_len;
 	/** Salt value, for unit tests (not all implementations support this) */
 	chunk_t salt;
+/** Use a salt length equal to the length of the hash */
 #define RSA_PSS_SALT_LEN_DEFAULT -1
+/** Use the maximum salt length depending on the hash and key length */
+#define RSA_PSS_SALT_LEN_MAX -2
 };
 
 /**
@@ -126,4 +130,15 @@ bool rsa_pss_params_parse(chunk_t asn1, int level0, rsa_pss_params_t *params);
  */
 bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1);
 
+/**
+ * Determine and set the salt length for the given params in case constants
+ * are used
+ *
+ * @param params	parameters to update
+ * @param modbits	RSA modulus length in bits (required if RSA_PSS_SALT_LEN_MAX
+ *					is used)
+ * @return			salt length to use, negative on error
+ */
+bool rsa_pss_params_set_salt_len(rsa_pss_params_t *params, size_t modbits);
+
 #endif /** SIGNATURE_PARAMS_H_ @}*/
diff --git a/src/libstrongswan/crypto/mac.h b/src/libstrongswan/crypto/mac.h
index 50dc4c73a..97cb7e352 100644
--- a/src/libstrongswan/crypto/mac.h
+++ b/src/libstrongswan/crypto/mac.h
@@ -39,12 +39,12 @@ struct mac_t {
 	 *
 	 * If out is NULL, no result is given back.  A next call will
 	 * append the data to already supplied data.  If out is not NULL,
-	 * the mac of all apended data is calculated, written to out and the
+	 * the MAC of all appended data is calculated, written to out and the
 	 * internal state is reset.
 	 *
 	 * @param data		chunk of data to authenticate
 	 * @param out		pointer where the generated bytes will be written
-	 * @return			TRUE if mac generated successfully
+	 * @return			TRUE if MAC generated successfully
 	 */
 	bool (*get_mac)(mac_t *this, chunk_t data,
 					uint8_t *out) __attribute__((warn_unused_result));
diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.c b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c
index cad94aa82..a078d3b30 100644
--- a/src/libstrongswan/crypto/proposal/proposal_keywords_static.c
+++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c
@@ -1,4 +1,4 @@
-/* C code produced by gperf version 3.0.4 */
+/* ANSI-C code produced by gperf version 3.1 */
 /* Command-line: /usr/bin/gperf -N proposal_get_token_static -m 10 -C -G -c -t -D  */
 /* Computed positions: -k'1,5-7,10,15,$' */
 
@@ -26,7 +26,7 @@
       && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
       && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
 /* The character set is not based on ISO-646.  */
-error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
 #endif
 
 
@@ -74,9 +74,7 @@ inline
 #endif
 #endif
 static unsigned int
-hash (str, len)
-     register const char *str;
-     register unsigned int len;
+hash (register const char *str, register size_t len)
 {
   static const unsigned char asso_values[] =
     {
@@ -107,7 +105,7 @@ hash (str, len)
       251, 251, 251, 251, 251, 251, 251, 251, 251, 251,
       251, 251, 251, 251, 251, 251, 251
     };
-  register int hval = len;
+  register unsigned int hval = len;
 
   switch (hval)
     {
@@ -320,22 +318,14 @@ static const short lookup[] =
     143
   };
 
-#ifdef __GNUC__
-__inline
-#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
 const struct proposal_token *
-proposal_get_token_static (str, len)
-     register const char *str;
-     register unsigned int len;
+proposal_get_token_static (register const char *str, register size_t len)
 {
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
     {
-      register int key = hash (str, len);
+      register unsigned int key = hash (str, len);
 
-      if (key <= MAX_HASH_VALUE && key >= 0)
+      if (key <= MAX_HASH_VALUE)
         {
           register int index = lookup[key];
 
diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.h b/src/libstrongswan/crypto/proposal/proposal_keywords_static.h
index 1345f36bb..a0beec0bb 100644
--- a/src/libstrongswan/crypto/proposal/proposal_keywords_static.h
+++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.h
@@ -19,7 +19,7 @@
 #include "proposal_keywords.h"
 
 const proposal_token_t* proposal_get_token_static(register const char *str,
-												  register unsigned len);
+												  register size_t len);
 
 #endif /* PROPOSAL_KEYWORDS_STATIC_H_ */
 
diff --git a/src/libstrongswan/plugins/agent/agent_private_key.c b/src/libstrongswan/plugins/agent/agent_private_key.c
index 77c29916c..db87affc9 100644
--- a/src/libstrongswan/plugins/agent/agent_private_key.c
+++ b/src/libstrongswan/plugins/agent/agent_private_key.c
@@ -81,6 +81,14 @@ enum agent_msg_type_t {
 	SSH_AGENT_SIGN_RESPONSE = 14,
 };
 
+/**
+ * Flags for signatures
+ */
+enum agent_signature_flags_t {
+	SSH_AGENT_FLAG_SHA2_256 = 2,
+	SSH_AGENT_FLAG_SHA2_512 = 4,
+};
+
 /**
  * read a byte from a blob
  */
@@ -217,12 +225,35 @@ static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
 }
 
 static bool scheme_supported(private_agent_private_key_t *this,
-							signature_scheme_t scheme)
+							 signature_scheme_t scheme, uint32_t *flags,
+							 char **prefix)
 {
 	switch (this->pubkey->get_type(this->pubkey))
 	{
 		case KEY_RSA:
-			return scheme == SIGN_RSA_EMSA_PKCS1_SHA1;
+			switch (scheme)
+			{
+				case SIGN_RSA_EMSA_PKCS1_SHA1:
+					*prefix = "ssh-rsa";
+					return TRUE;
+				case SIGN_RSA_EMSA_PKCS1_SHA2_256:
+					*flags |= SSH_AGENT_FLAG_SHA2_256;
+					*prefix = "rsa-sha2-256";
+					return TRUE;
+				case SIGN_RSA_EMSA_PKCS1_SHA2_512:
+					*flags |= SSH_AGENT_FLAG_SHA2_512;
+					*prefix = "rsa-sha2-512";
+					return TRUE;
+				default:
+					break;
+			}
+			return FALSE;
+		case KEY_ED25519:
+			*prefix = "ssh-ed25519";
+			return scheme == SIGN_ED25519;
+		case KEY_ED448:
+			*prefix = "ssh-ed448";
+			return scheme == SIGN_ED448;
 		case KEY_ECDSA:
 			return scheme == SIGN_ECDSA_256 ||
 				   scheme == SIGN_ECDSA_384 ||
@@ -236,11 +267,12 @@ METHOD(private_key_t, sign, bool,
 	private_agent_private_key_t *this, signature_scheme_t scheme, void *params,
 	chunk_t data, chunk_t *signature)
 {
-	uint32_t len, flags;
-	char buf[2048];
+	key_type_t type;
+	uint32_t len, flags = 0;
+	char buf[2048], *prefix = NULL;
 	chunk_t blob;
 
-	if (!scheme_supported(this, scheme))
+	if (!scheme_supported(this, scheme, &flags, &prefix))
 	{
 		DBG1(DBG_LIB, "signature scheme %N not supported by ssh-agent",
 			 signature_scheme_names, scheme);
@@ -272,7 +304,7 @@ METHOD(private_key_t, sign, bool,
 		return FALSE;
 	}
 
-	flags = htonl(0);
+	flags = htonl(flags);
 	if (write(this->socket, &flags, sizeof(flags)) != sizeof(flags))
 	{
 		DBG1(DBG_LIB, "writing to ssh-agent failed");
@@ -290,9 +322,15 @@ METHOD(private_key_t, sign, bool,
 	}
 	/* parse length */
 	blob = read_string(&blob);
-	/* check sig type */
-	if (chunk_equals(read_string(&blob), chunk_from_str("ssh-rsa")))
-	{	/* for RSA the signature has no special encoding */
+	/* verify type */
+	if (prefix && !chunk_equals(read_string(&blob), chunk_from_str(prefix)))
+	{
+		DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix);
+		return FALSE;
+	}
+	type = this->pubkey->get_type(this->pubkey);
+	if (type == KEY_RSA || type == KEY_ED25519 || type == KEY_ED448)
+	{	/* for RSA/EdDSA, the signature has no special encoding */
 		blob = read_string(&blob);
 		if (blob.len)
 		{
@@ -301,7 +339,7 @@ METHOD(private_key_t, sign, bool,
 		}
 	}
 	else
-	{	/* anything else is treated as ECSDA for now */
+	{	/* parse ECDSA signatures */
 		blob = read_string(&blob);
 		if (blob.len)
 		{
@@ -340,6 +378,80 @@ METHOD(private_key_t, get_keysize, int,
 	return this->pubkey->get_keysize(this->pubkey);
 }
 
+/**
+ * Private data for RSA scheme enumerator
+ */
+typedef struct {
+	enumerator_t public;
+	int index;
+	bool reverse;
+} scheme_enumerator_t;
+
+static signature_params_t rsa_schemes[] = {
+	{ .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256 },
+	{ .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_512 },
+};
+
+METHOD(enumerator_t, enumerate_rsa_scheme, bool,
+	scheme_enumerator_t *this, va_list args)
+{
+	signature_params_t **params;
+
+	VA_ARGS_VGET(args, params);
+
+	if ((this->reverse && --this->index >= 0) ||
+	   (!this->reverse && ++this->index < countof(rsa_schemes)))
+	{
+		*params = &rsa_schemes[this->index];
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/**
+ * Create an enumerator for the supported RSA signature schemes
+ */
+static enumerator_t *create_rsa_enumerator(private_agent_private_key_t *this)
+{
+	scheme_enumerator_t *enumerator;
+
+	INIT(enumerator,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_rsa_scheme,
+			.destroy = (void*)free,
+		},
+		.index = -1,
+		.reverse = FALSE,
+	);
+	/* propose SHA-512 first for larger keys */
+	if (get_keysize(this) > 3072)
+	{
+		enumerator->index = countof(rsa_schemes);
+		enumerator->reverse = TRUE;
+	}
+	return &enumerator->public;
+}
+
+METHOD(private_key_t, supported_signature_schemes, enumerator_t*,
+	private_agent_private_key_t *this)
+{
+	key_type_t type = get_type(this);
+
+	switch (type)
+	{
+		case KEY_RSA:
+			return create_rsa_enumerator(this);
+		case KEY_ED25519:
+		case KEY_ED448:
+		case KEY_ECDSA:
+			return signature_schemes_for_key(type, get_keysize(this));
+		default:
+			break;
+	}
+	return enumerator_create_empty();
+}
+
 METHOD(private_key_t, get_public_key, public_key_t*,
 	private_agent_private_key_t *this)
 {
@@ -413,6 +525,7 @@ agent_private_key_t *agent_private_key_open(key_type_t type, va_list args)
 		.public = {
 			.key = {
 				.get_type = _get_type,
+				.supported_signature_schemes = _supported_signature_schemes,
 				.sign = _sign,
 				.decrypt = _decrypt,
 				.get_keysize = _get_keysize,
diff --git a/src/libstrongswan/plugins/botan/Makefile.am b/src/libstrongswan/plugins/botan/Makefile.am
index c1160145a..30d3e601c 100644
--- a/src/libstrongswan/plugins/botan/Makefile.am
+++ b/src/libstrongswan/plugins/botan/Makefile.am
@@ -23,9 +23,11 @@ libstrongswan_botan_la_SOURCES = \
 	botan_ec_diffie_hellman.h botan_ec_diffie_hellman.c \
 	botan_ec_public_key.h botan_ec_public_key.c \
 	botan_ec_private_key.h botan_ec_private_key.c \
+	botan_ed_public_key.h botan_ed_public_key.c \
+	botan_ed_private_key.h botan_ed_private_key.c \
 	botan_util.h botan_util.c \
 	botan_util_keys.h botan_util_keys.c \
-	botan_gcm.h botan_gcm.c \
+	botan_aead.h botan_aead.c \
 	botan_x25519.h botan_x25519.c
 
 libstrongswan_botan_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/botan/Makefile.in b/src/libstrongswan/plugins/botan/Makefile.in
index ef9f88610..3bb3e22f4 100644
--- a/src/libstrongswan/plugins/botan/Makefile.in
+++ b/src/libstrongswan/plugins/botan/Makefile.in
@@ -142,8 +142,9 @@ am_libstrongswan_botan_la_OBJECTS = botan_plugin.lo botan_rng.lo \
 	botan_hasher.lo botan_hmac.lo botan_crypter.lo \
 	botan_rsa_public_key.lo botan_rsa_private_key.lo \
 	botan_diffie_hellman.lo botan_ec_diffie_hellman.lo \
-	botan_ec_public_key.lo botan_ec_private_key.lo botan_util.lo \
-	botan_util_keys.lo botan_gcm.lo botan_x25519.lo
+	botan_ec_public_key.lo botan_ec_private_key.lo \
+	botan_ed_public_key.lo botan_ed_private_key.lo botan_util.lo \
+	botan_util_keys.lo botan_aead.lo botan_x25519.lo
 libstrongswan_botan_la_OBJECTS = $(am_libstrongswan_botan_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -478,9 +479,11 @@ libstrongswan_botan_la_SOURCES = \
 	botan_ec_diffie_hellman.h botan_ec_diffie_hellman.c \
 	botan_ec_public_key.h botan_ec_public_key.c \
 	botan_ec_private_key.h botan_ec_private_key.c \
+	botan_ed_public_key.h botan_ed_public_key.c \
+	botan_ed_private_key.h botan_ed_private_key.c \
 	botan_util.h botan_util.c \
 	botan_util_keys.h botan_util_keys.c \
-	botan_gcm.h botan_gcm.c \
+	botan_aead.h botan_aead.c \
 	botan_x25519.h botan_x25519.c
 
 libstrongswan_botan_la_LDFLAGS = -module -avoid-version
@@ -574,12 +577,14 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_aead.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_crypter.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_diffie_hellman.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_ec_diffie_hellman.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_ec_private_key.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_ec_public_key.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_gcm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_ed_private_key.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_ed_public_key.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_hasher.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_hmac.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan_plugin.Plo@am__quote@
diff --git a/src/libstrongswan/plugins/botan/botan_aead.c b/src/libstrongswan/plugins/botan/botan_aead.c
new file mode 100644
index 000000000..40006ae77
--- /dev/null
+++ b/src/libstrongswan/plugins/botan/botan_aead.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Copyright (C) 2018 Atanas Filyanov
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_aead.h"
+
+#include <botan/build.h>
+
+#if (defined(BOTAN_HAS_AES) && \
+		(defined(BOTAN_HAS_AEAD_GCM) || defined(BOTAN_HAS_AEAD_CCM))) || \
+	defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
+
+#include <crypto/iv/iv_gen_seq.h>
+
+#include <botan/ffi.h>
+
+/**
+ * As defined in RFC 4106 (GCM) and RFC 7634 (ChaPoly)
+ */
+#define IV_LEN			8
+#define SALT_LEN		4
+#define CHAPOLY_KEY_LEN	32
+/**
+ * As defined in RFC 4309
+ */
+#define CCM_SALT_LEN	3
+
+typedef struct private_aead_t private_aead_t;
+
+struct private_aead_t {
+
+	/**
+	 * Public interface
+	 */
+	aead_t public;
+
+	/**
+	 * The encryption key
+	 */
+	chunk_t	key;
+
+	/**
+	 * Salt value
+	 */
+	chunk_t salt;
+
+	/**
+	 * Size of the integrity check value
+	 */
+	size_t icv_size;
+
+	/**
+	 * IV generator
+	 */
+	iv_gen_t *iv_gen;
+
+	/**
+	 * The cipher to use
+	 */
+	const char* cipher_name;
+};
+
+/**
+ * Do the actual en/decryption
+ */
+static bool do_crypt(private_aead_t *this, chunk_t data, chunk_t assoc,
+					 chunk_t iv, u_char *out, uint32_t init_flag)
+{
+	botan_cipher_t cipher;
+	size_t output_written = 0, input_consumed = 0;
+	chunk_t nonce;
+
+	if (botan_cipher_init(&cipher, this->cipher_name, init_flag))
+	{
+		return FALSE;
+	}
+
+	if (botan_cipher_set_key(cipher, this->key.ptr, this->key.len))
+	{
+		botan_cipher_destroy(cipher);
+		return FALSE;
+	}
+
+	if (assoc.len &&
+		botan_cipher_set_associated_data(cipher, assoc.ptr, assoc.len))
+	{
+		botan_cipher_destroy(cipher);
+		return FALSE;
+	}
+
+	nonce = chunk_cata("cc", this->salt, iv);
+
+	if (botan_cipher_start(cipher, nonce.ptr, nonce.len))
+	{
+		botan_cipher_destroy(cipher);
+		return FALSE;
+	}
+
+	if (init_flag == BOTAN_CIPHER_INIT_FLAG_ENCRYPT)
+	{
+		if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
+								out, data.len + this->icv_size, &output_written,
+								data.ptr, data.len, &input_consumed))
+		{
+			botan_cipher_destroy(cipher);
+			return FALSE;
+		}
+	}
+	else if (init_flag == BOTAN_CIPHER_INIT_FLAG_DECRYPT)
+	{
+		if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
+								out, data.len, &output_written, data.ptr,
+								data.len + this->icv_size, &input_consumed))
+		{
+			botan_cipher_destroy(cipher);
+			return FALSE;
+		}
+	}
+
+	botan_cipher_destroy(cipher);
+
+	return TRUE;
+}
+
+METHOD(aead_t, encrypt, bool,
+	private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
+	chunk_t *encrypted)
+{
+	u_char *out;
+
+	out = plain.ptr;
+	if (encrypted)
+	{
+		*encrypted = chunk_alloc(plain.len + this->icv_size);
+		out = encrypted->ptr;
+	}
+	return do_crypt(this, plain, assoc, iv, out,
+					BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
+}
+
+METHOD(aead_t, decrypt, bool,
+	private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
+	chunk_t *plain)
+{
+	u_char *out;
+
+	if (encrypted.len < this->icv_size)
+	{
+		return FALSE;
+	}
+	encrypted.len -= this->icv_size;
+
+	out = encrypted.ptr;
+	if (plain)
+	{
+		*plain = chunk_alloc(encrypted.len);
+		out = plain->ptr;
+	}
+	return do_crypt(this, encrypted, assoc, iv, out,
+					BOTAN_CIPHER_INIT_FLAG_DECRYPT);
+}
+
+METHOD(aead_t, get_block_size, size_t,
+	private_aead_t *this)
+{
+	return 1;
+}
+
+METHOD(aead_t, get_icv_size, size_t,
+	private_aead_t *this)
+{
+	return this->icv_size;
+}
+
+METHOD(aead_t, get_iv_size, size_t,
+	private_aead_t *this)
+{
+	return IV_LEN;
+}
+
+METHOD(aead_t, get_iv_gen, iv_gen_t*,
+	private_aead_t *this)
+{
+	return this->iv_gen;
+}
+
+METHOD(aead_t, get_key_size, size_t,
+	private_aead_t *this)
+{
+	return this->key.len + this->salt.len;
+}
+
+METHOD(aead_t, set_key, bool,
+	private_aead_t *this, chunk_t key)
+{
+	if (key.len != get_key_size(this))
+	{
+		return FALSE;
+	}
+	memcpy(this->salt.ptr, key.ptr + key.len - this->salt.len, this->salt.len);
+	memcpy(this->key.ptr, key.ptr, this->key.len);
+	return TRUE;
+}
+
+METHOD(aead_t, destroy, void,
+	private_aead_t *this)
+{
+	chunk_clear(&this->key);
+	chunk_clear(&this->salt);
+	this->iv_gen->destroy(this->iv_gen);
+	free(this);
+}
+
+#ifdef BOTAN_HAS_AES
+#if defined(BOTAN_HAS_AEAD_GCM) || defined(BOTAN_HAS_AEAD_GCM)
+
+static struct {
+	encryption_algorithm_t algo;
+	size_t key_size;
+	char *name;
+	size_t icv_size;
+} aes_modes[] = {
+	{ ENCR_AES_GCM_ICV8,  16, "AES-128/GCM(8)",     8 },
+	{ ENCR_AES_GCM_ICV8,  24, "AES-192/GCM(8)",     8 },
+	{ ENCR_AES_GCM_ICV8,  32, "AES-256/GCM(8)",     8 },
+	{ ENCR_AES_GCM_ICV12, 16, "AES-128/GCM(12)",   12 },
+	{ ENCR_AES_GCM_ICV12, 24, "AES-192/GCM(12)",   12 },
+	{ ENCR_AES_GCM_ICV12, 32, "AES-256/GCM(12)",   12 },
+	{ ENCR_AES_GCM_ICV16, 16, "AES-128/GCM(16)",   16 },
+	{ ENCR_AES_GCM_ICV16, 24, "AES-192/GCM(16)",   16 },
+	{ ENCR_AES_GCM_ICV16, 32, "AES-256/GCM(16)",   16 },
+	{ ENCR_AES_CCM_ICV8,  16, "AES-128/CCM(8,4)",   8 },
+	{ ENCR_AES_CCM_ICV8,  24, "AES-192/CCM(8,4)",   8 },
+	{ ENCR_AES_CCM_ICV8,  32, "AES-256/CCM(8,4)",   8 },
+	{ ENCR_AES_CCM_ICV12, 16, "AES-128/CCM(12,4)", 12 },
+	{ ENCR_AES_CCM_ICV12, 24, "AES-192/CCM(12,4)", 12 },
+	{ ENCR_AES_CCM_ICV12, 32, "AES-256/CCM(12,4)", 12 },
+	{ ENCR_AES_CCM_ICV16, 16, "AES-128/CCM(16,4)", 16 },
+	{ ENCR_AES_CCM_ICV16, 24, "AES-192/CCM(16,4)", 16 },
+	{ ENCR_AES_CCM_ICV16, 32, "AES-256/CCM(16,4)", 16 },
+};
+
+/**
+ * Determine the cipher name and ICV size for the given algorithm and key size
+ */
+static bool determine_aes_params(private_aead_t *this,
+								 encryption_algorithm_t algo, size_t key_size)
+{
+	int i;
+
+	for (i = 0; i < countof(aes_modes); i++)
+	{
+		if (aes_modes[i].algo == algo &&
+			aes_modes[i].key_size == key_size)
+		{
+			this->cipher_name = aes_modes[i].name;
+			this->icv_size = aes_modes[i].icv_size;
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+#endif
+#endif
+
+/**
+ * Check the given salt size, set it if not set
+ */
+static bool check_salt_size(size_t expected, size_t *salt_size)
+{
+	if (*salt_size)
+	{
+		return *salt_size == expected;
+	}
+	*salt_size = expected;
+	return TRUE;
+}
+
+/*
+ * Described in header
+ */
+aead_t *botan_aead_create(encryption_algorithm_t algo, size_t key_size,
+						  size_t salt_size)
+{
+	private_aead_t *this;
+
+	INIT(this,
+		.public = {
+			.encrypt = _encrypt,
+			.decrypt = _decrypt,
+			.get_block_size = _get_block_size,
+			.get_icv_size = _get_icv_size,
+			.get_iv_size = _get_iv_size,
+			.get_iv_gen = _get_iv_gen,
+			.get_key_size = _get_key_size,
+			.set_key = _set_key,
+			.destroy = _destroy,
+		},
+	);
+
+	switch (algo)
+	{
+#ifdef BOTAN_HAS_AES
+#ifdef BOTAN_HAS_AEAD_GCM
+		case ENCR_AES_GCM_ICV8:
+		case ENCR_AES_GCM_ICV12:
+		case ENCR_AES_GCM_ICV16:
+			if (!key_size)
+			{
+				key_size = 16;
+			}
+			if (!check_salt_size(SALT_LEN, &salt_size) ||
+				!determine_aes_params(this, algo, key_size))
+			{
+				free(this);
+				return NULL;
+			}
+			break;
+#endif
+#ifdef BOTAN_HAS_AEAD_CCM
+		case ENCR_AES_CCM_ICV8:
+		case ENCR_AES_CCM_ICV12:
+		case ENCR_AES_CCM_ICV16:
+			if (!key_size)
+			{
+				key_size = 16;
+			}
+			if (!check_salt_size(CCM_SALT_LEN, &salt_size) ||
+				!determine_aes_params(this, algo, key_size))
+			{
+				free(this);
+				return NULL;
+			}
+			break;
+#endif
+#endif
+#ifdef BOTAN_HAS_AEAD_CHACHA20_POLY1305
+		case ENCR_CHACHA20_POLY1305:
+			if (!key_size)
+			{
+				key_size = CHAPOLY_KEY_LEN;
+			}
+			if (key_size != CHAPOLY_KEY_LEN ||
+				!check_salt_size(SALT_LEN, &salt_size))
+			{
+				free(this);
+				return NULL;
+			}
+			this->cipher_name = "ChaCha20Poly1305";
+			this->icv_size = 16;
+			break;
+#endif
+		default:
+			free(this);
+			return NULL;
+	}
+
+	this->key = chunk_alloc(key_size);
+	this->salt = chunk_alloc(salt_size);
+	this->iv_gen = iv_gen_seq_create();
+
+	return &this->public;
+}
+
+#endif
diff --git a/src/libstrongswan/plugins/botan/botan_aead.h b/src/libstrongswan/plugins/botan/botan_aead.h
new file mode 100644
index 000000000..00a2ba4bc
--- /dev/null
+++ b/src/libstrongswan/plugins/botan/botan_aead.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Copyright (C) 2018 Atanas Filyanov
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Implements the aead_t interface using Botan.
+ *
+ * @defgroup botan_aead botan_aead
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_AEAD_H_
+#define BOTAN_AEAD_H_
+
+#include <crypto/aead.h>
+
+/**
+ * Constructor to create aead_t implementation.
+ *
+ * @param algo			algorithm to implement
+ * @param key_size		key size in bytes
+ * @param salt_size		size of implicit salt length
+ * @return				aead_t object, NULL if not supported
+ */
+aead_t *botan_aead_create(encryption_algorithm_t algo, size_t key_size,
+						  size_t salt_size);
+
+#endif /** BOTAN_AEAD_H_ @}*/
diff --git a/src/libstrongswan/plugins/botan/botan_crypter.c b/src/libstrongswan/plugins/botan/botan_crypter.c
index 002be6ea8..3ec5c4d5e 100644
--- a/src/libstrongswan/plugins/botan/botan_crypter.c
+++ b/src/libstrongswan/plugins/botan/botan_crypter.c
@@ -25,6 +25,10 @@
 
 #include "botan_crypter.h"
 
+#include <botan/build.h>
+
+#if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_MODE_CBC)
+
 #include <botan/ffi.h>
 
 typedef struct private_botan_crypter_t private_botan_crypter_t;
@@ -189,3 +193,5 @@ botan_crypter_t *botan_crypter_create(encryption_algorithm_t algo,
 	this->key = chunk_alloc(key_size);
 	return &this->public;
 }
+
+#endif
diff --git a/src/libstrongswan/plugins/botan/botan_ec_public_key.c b/src/libstrongswan/plugins/botan/botan_ec_public_key.c
index 4c85dbcec..095ae3f20 100644
--- a/src/libstrongswan/plugins/botan/botan_ec_public_key.c
+++ b/src/libstrongswan/plugins/botan/botan_ec_public_key.c
@@ -69,9 +69,7 @@ static bool verify_signature(private_botan_ec_public_key_t *this,
 	const char* hash_and_padding, int signature_format, size_t keylen,
 	chunk_t data, chunk_t signature)
 {
-	botan_pk_op_verify_t verify_op;
 	chunk_t sig = signature;
-	bool valid = FALSE;
 
 	if (signature_format == SIG_FORMAT_DER_SEQUENCE)
 	{
@@ -104,22 +102,7 @@ static bool verify_signature(private_botan_ec_public_key_t *this,
 		memcpy(sig.ptr + (keylen - r.len), r.ptr, r.len);
 		memcpy(sig.ptr + keylen + (keylen - s.len), s.ptr, s.len);
 	}
-
-	if (botan_pk_op_verify_create(&verify_op, this->key, hash_and_padding, 0))
-	{
-		return FALSE;
-	}
-
-	if (botan_pk_op_verify_update(verify_op, data.ptr, data.len))
-	{
-		botan_pk_op_verify_destroy(verify_op);
-		return FALSE;
-	}
-
-	valid = !(botan_pk_op_verify_finish(verify_op, sig.ptr, sig.len));
-
-	botan_pk_op_verify_destroy(verify_op);
-	return valid;
+	return botan_verify_signature(this->key, hash_and_padding, data, sig);
 }
 
 METHOD(public_key_t, get_type, key_type_t,
diff --git a/src/libstrongswan/plugins/botan/botan_ed_private_key.c b/src/libstrongswan/plugins/botan/botan_ed_private_key.c
new file mode 100644
index 000000000..3f0f54222
--- /dev/null
+++ b/src/libstrongswan/plugins/botan/botan_ed_private_key.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_ed_private_key.h"
+#include "botan_ed_public_key.h"
+#include "botan_util.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_ED25519
+
+#include <asn1/asn1.h>
+#include <utils/debug.h>
+
+typedef struct private_private_key_t private_private_key_t;
+
+#define ED25519_KEY_LEN 32
+
+/**
+ * Private data
+ */
+struct private_private_key_t {
+
+	/**
+	 * Public interface
+	 */
+	private_key_t public;
+
+	/**
+	 * Botan private key object
+	 */
+	botan_privkey_t key;
+
+	/**
+	 * Reference count
+	 */
+	refcount_t ref;
+};
+
+METHOD(private_key_t, sign, bool,
+	private_private_key_t *this, signature_scheme_t scheme,
+	void *params, chunk_t data, chunk_t *signature)
+{
+	switch (scheme)
+	{
+		case SIGN_ED25519:
+			return botan_get_signature(this->key, "Pure", data, signature);
+		default:
+			DBG1(DBG_LIB, "signature scheme %N not supported via botan",
+				 signature_scheme_names, scheme);
+			return FALSE;
+	}
+}
+
+METHOD(private_key_t, decrypt, bool,
+	private_private_key_t *this, encryption_scheme_t scheme,
+	chunk_t crypto, chunk_t *plain)
+{
+	DBG1(DBG_LIB, "EdDSA private key decryption not implemented");
+	return FALSE;
+}
+
+METHOD(private_key_t, get_keysize, int,
+	private_private_key_t *this)
+{
+	return ED25519_KEY_LEN * 8;
+}
+
+METHOD(private_key_t, get_type, key_type_t,
+	private_private_key_t *this)
+{
+	return KEY_ED25519;
+}
+
+METHOD(private_key_t, get_public_key, public_key_t*,
+	private_private_key_t *this)
+{
+	botan_pubkey_t pubkey;
+
+	if (botan_privkey_export_pubkey(&pubkey, this->key))
+	{
+		return NULL;
+	}
+	return botan_ed_public_key_adopt(pubkey);
+}
+
+METHOD(private_key_t, get_fingerprint, bool,
+	private_private_key_t *this, cred_encoding_type_t type,
+	chunk_t *fingerprint)
+{
+	botan_pubkey_t pubkey;
+	bool success = FALSE;
+
+	/* check the cache before doing the export */
+	if (lib->encoding->get_cache(lib->encoding, type, this, fingerprint))
+	{
+		return TRUE;
+	}
+
+	if (botan_privkey_export_pubkey(&pubkey, this->key))
+	{
+		return FALSE;
+	}
+	success = botan_get_fingerprint(pubkey, this, type, fingerprint);
+	botan_pubkey_destroy(pubkey);
+	return success;
+}
+
+METHOD(private_key_t, get_encoding, bool,
+	private_private_key_t *this, cred_encoding_type_t type,
+	chunk_t *encoding)
+{
+	return botan_get_privkey_encoding(this->key, type, encoding);
+}
+
+METHOD(private_key_t, get_ref, private_key_t*,
+	private_private_key_t *this)
+{
+	ref_get(&this->ref);
+	return &this->public;
+}
+
+METHOD(private_key_t, destroy, void,
+	private_private_key_t *this)
+{
+	if (ref_put(&this->ref))
+	{
+		lib->encoding->clear_cache(lib->encoding, this);
+		botan_privkey_destroy(this->key);
+		free(this);
+	}
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_private_key_t *create_empty()
+{
+	private_private_key_t *this;
+
+	INIT(this,
+		.public = {
+			.get_type = _get_type,
+			.sign = _sign,
+			.decrypt = _decrypt,
+			.get_keysize = _get_keysize,
+			.get_public_key = _get_public_key,
+			.equals = private_key_equals,
+			.belongs_to = private_key_belongs_to,
+			.get_fingerprint = _get_fingerprint,
+			.has_fingerprint = private_key_has_fingerprint,
+			.get_encoding = _get_encoding,
+			.get_ref = _get_ref,
+			.destroy = _destroy,
+		},
+		.ref = 1,
+	);
+
+	return this;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *botan_ed_private_key_adopt(botan_privkey_t key)
+{
+	private_private_key_t *this;
+
+	this = create_empty();
+	this->key = key;
+
+	return &this->public;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *botan_ed_private_key_gen(key_type_t type, va_list args)
+{
+	private_private_key_t *this;
+	botan_rng_t rng;
+
+	while (TRUE)
+	{
+		switch (va_arg(args, builder_part_t))
+		{
+			case BUILD_KEY_SIZE:
+				/* just ignore the key size */
+				va_arg(args, u_int);
+				continue;
+			case BUILD_END:
+				break;
+			default:
+				return NULL;
+		}
+		break;
+	}
+
+	if (botan_rng_init(&rng, "system"))
+	{
+		return NULL;
+	}
+
+	this = create_empty();
+
+	if (botan_privkey_create(&this->key, "Ed25519", NULL, rng))
+	{
+		DBG1(DBG_LIB, "EdDSA private key generation failed");
+		botan_rng_destroy(rng);
+		free(this);
+		return NULL;
+	}
+
+	botan_rng_destroy(rng);
+	return &this->public;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *botan_ed_private_key_load(key_type_t type, va_list args)
+{
+	private_private_key_t *this;
+	chunk_t key = chunk_empty;
+
+	while (TRUE)
+	{
+		switch (va_arg(args, builder_part_t))
+		{
+			case BUILD_EDDSA_PRIV_ASN1_DER:
+				key = va_arg(args, chunk_t);
+				continue;
+			case BUILD_END:
+				break;
+			default:
+				return NULL;
+		}
+		break;
+	}
+
+	/* PKCS#8-encoded keys are handled generically, so we only handle the
+	 * explicit case */
+	if (asn1_unwrap(&key, &key) != ASN1_OCTET_STRING ||
+		key.len != ED25519_KEY_LEN)
+	{
+		return NULL;
+	}
+
+	this = create_empty();
+
+	if (botan_privkey_load_ed25519(&this->key, key.ptr))
+	{
+		free(this);
+		return NULL;
+	}
+	return &this->public;
+}
+
+#endif
diff --git a/src/libstrongswan/plugins/botan/botan_ed_private_key.h b/src/libstrongswan/plugins/botan/botan_ed_private_key.h
new file mode 100644
index 000000000..f7f32e8f3
--- /dev/null
+++ b/src/libstrongswan/plugins/botan/botan_ed_private_key.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_ed_private_key botan_ed_private_key
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_ED_PRIVATE_KEY_H_
+#define BOTAN_ED_PRIVATE_KEY_H_
+
+#include <botan/ffi.h>
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+/**
+ * Generate an EdDSA private key using Botan.
+ *
+ * @param type		type of the key, must be KEY_ED25519
+ * @param args		builder_part_t argument list
+ * @return 			generated key, NULL on failure
+ */
+private_key_t *botan_ed_private_key_gen(key_type_t type, va_list args);
+
+/**
+ * Load an EdDSA private key using Botan.
+ *
+ * @param type		type of the key, must be KEY_ED25519
+ * @param args		builder_part_t argument list
+ * @return 			loaded key, NULL on failure
+ */
+private_key_t *botan_ed_private_key_load(key_type_t type, va_list args);
+
+/**
+ * Load an EdDSA private key by adopting a botan_privkey_t object.
+ *
+ * @param key		private key object (adopted)
+ * @return			loaded key, NULL on failure
+ */
+private_key_t *botan_ed_private_key_adopt(botan_privkey_t key);
+
+#endif /** BOTAN_ED_PRIVATE_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/botan/botan_ed_public_key.c b/src/libstrongswan/plugins/botan/botan_ed_public_key.c
new file mode 100644
index 000000000..41d2baae8
--- /dev/null
+++ b/src/libstrongswan/plugins/botan/botan_ed_public_key.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_ed_public_key.h"
+#include "botan_util.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_ED25519
+
+#include <utils/debug.h>
+
+typedef struct private_public_key_t private_public_key_t;
+
+/**
+ * Private data
+ */
+struct private_public_key_t {
+
+	/**
+	 * Public interface
+	 */
+	public_key_t public;
+
+	/**
+	 * Botan public key object
+	 */
+	botan_pubkey_t key;
+
+	/**
+	 * Reference counter
+	 */
+	refcount_t ref;
+};
+
+METHOD(public_key_t, get_type, key_type_t,
+	private_public_key_t *this)
+{
+	return KEY_ED25519;
+}
+
+METHOD(public_key_t, get_keysize, int,
+	private_public_key_t *this)
+{
+	return ED25519_KEY_LEN * 8;
+}
+
+METHOD(public_key_t, verify, bool,
+	private_public_key_t *this, signature_scheme_t scheme,
+	void *params, chunk_t data, chunk_t signature)
+{
+	switch (scheme)
+	{
+		case SIGN_ED25519:
+			return botan_verify_signature(this->key, "Pure", data, signature);
+		default:
+			DBG1(DBG_LIB, "signature scheme %N not supported via botan",
+				 signature_scheme_names, scheme);
+			return FALSE;
+	}
+}
+
+METHOD(public_key_t, encrypt, bool,
+	private_public_key_t *this, encryption_scheme_t scheme,
+	chunk_t crypto, chunk_t *plain)
+{
+	DBG1(DBG_LIB, "EdDSA public key encryption not implemented");
+	return FALSE;
+}
+
+METHOD(public_key_t, get_fingerprint, bool,
+	private_public_key_t *this, cred_encoding_type_t type,
+	chunk_t *fingerprint)
+{
+	return botan_get_fingerprint(this->key, this, type, fingerprint);
+}
+
+METHOD(public_key_t, get_encoding, bool,
+	private_public_key_t *this, cred_encoding_type_t type,
+	chunk_t *encoding)
+{
+	return botan_get_encoding(this->key, type, encoding);
+}
+
+METHOD(public_key_t, get_ref, public_key_t*,
+	private_public_key_t *this)
+{
+	ref_get(&this->ref);
+	return &this->public;
+}
+
+METHOD(public_key_t, destroy, void,
+	private_public_key_t *this)
+{
+	if (ref_put(&this->ref))
+	{
+		lib->encoding->clear_cache(lib->encoding, this);
+		botan_pubkey_destroy(this->key);
+		free(this);
+	}
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_public_key_t *create_empty()
+{
+	private_public_key_t *this;
+
+	INIT(this,
+		.public = {
+			.get_type = _get_type,
+			.verify = _verify,
+			.encrypt = _encrypt,
+			.get_keysize = _get_keysize,
+			.equals = public_key_equals,
+			.get_fingerprint = _get_fingerprint,
+			.has_fingerprint = public_key_has_fingerprint,
+			.get_encoding = _get_encoding,
+			.get_ref = _get_ref,
+			.destroy = _destroy,
+		},
+		.ref = 1,
+	);
+
+	return this;
+}
+
+/*
+ * Described in header
+ */
+public_key_t *botan_ed_public_key_adopt(botan_pubkey_t key)
+{
+	private_public_key_t *this;
+
+	this = create_empty();
+	this->key = key;
+
+	return &this->public;
+}
+
+/*
+ * Described in header
+ */
+public_key_t *botan_ed_public_key_load(key_type_t type, va_list args)
+{
+	private_public_key_t *this;
+	chunk_t key = chunk_empty;
+
+	while (TRUE)
+	{
+		switch (va_arg(args, builder_part_t))
+		{
+			case BUILD_EDDSA_PUB:
+				key = va_arg(args, chunk_t);
+				continue;
+			case BUILD_END:
+				break;
+			default:
+				return NULL;
+		}
+		break;
+	}
+
+	/* ASN.1-encoded keys are handled generically, so we only handle the
+	 * explicit case */
+	if (key.len != ED25519_KEY_LEN)
+	{
+		return NULL;
+	}
+
+	this = create_empty();
+
+	if (botan_pubkey_load_ed25519(&this->key, key.ptr))
+	{
+		free(this);
+		return NULL;
+	}
+	return &this->public;
+}
+
+#endif
diff --git a/src/libstrongswan/plugins/botan/botan_ed_public_key.h b/src/libstrongswan/plugins/botan/botan_ed_public_key.h
new file mode 100644
index 000000000..0f44b1afb
--- /dev/null
+++ b/src/libstrongswan/plugins/botan/botan_ed_public_key.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef BOTAN_ED_PUBLIC_KEY_H_
+#define BOTAN_ED_PUBLIC_KEY_H_
+
+#include <botan/ffi.h>
+
+#include <credentials/builder.h>
+#include <credentials/keys/public_key.h>
+
+#define ED25519_KEY_LEN 32
+
+/**
+ * Load an EdDSA public key by adopting a botan_pubkey_t object.
+ *
+ * @param key		public key object (adopted)
+ * @return			loaded key, NULL on failure
+ */
+public_key_t *botan_ed_public_key_adopt(botan_pubkey_t key);
+
+/**
+ * Load an EdDSA public key using Botan.
+ *
+ * @param type		type of the key, must be KEY_ED25519
+ * @param args		builder_part_t argument list
+ * @return 			loaded key, NULL on failure
+ */
+public_key_t *botan_ed_public_key_load(key_type_t type, va_list args);
+
+#endif /** BOTAN_ED_PUBLIC_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/botan/botan_gcm.c b/src/libstrongswan/plugins/botan/botan_gcm.c
deleted file mode 100644
index 7e0fc1468..000000000
--- a/src/libstrongswan/plugins/botan/botan_gcm.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2018 Atanas Filyanov
- * Rohde & Schwarz Cybersecurity GmbH
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "botan_gcm.h"
-
-#include <botan/build.h>
-
-#ifdef BOTAN_HAS_AES
-#ifdef BOTAN_HAS_AEAD_GCM
-
-#include <crypto/iv/iv_gen_seq.h>
-
-#include <botan/ffi.h>
-
-/**
- * as defined in RFC 4106
- */
-#define IV_LEN		8
-#define SALT_LEN	4
-#define NONCE_LEN	(IV_LEN + SALT_LEN)
-
-typedef struct private_aead_t private_aead_t;
-
-struct private_aead_t {
-
-	/**
-	 * Public interface
-	 */
-	aead_t public;
-
-	/**
-	 * The encryption key
-	 */
-	chunk_t	key;
-
-	/**
-	 * Salt value
-	 */
-	char salt[SALT_LEN];
-
-	/**
-	 * Size of the integrity check value
-	 */
-	size_t icv_size;
-
-	/**
-	 * IV generator
-	 */
-	iv_gen_t *iv_gen;
-
-	/**
-	 * The cipher to use
-	 */
-	const char* cipher_name;
-};
-
-/**
- * Do the actual en/decryption
- */
-static bool crypt(private_aead_t *this, chunk_t data, chunk_t assoc, chunk_t iv,
-				  u_char *out, uint32_t init_flag)
-{
-	botan_cipher_t cipher;
-	uint8_t nonce[NONCE_LEN];
-	size_t output_written = 0, input_consumed = 0;
-
-	memcpy(nonce, this->salt, SALT_LEN);
-	memcpy(nonce + SALT_LEN, iv.ptr, IV_LEN);
-
-	if (botan_cipher_init(&cipher, this->cipher_name, init_flag))
-	{
-		return FALSE;
-	}
-
-	if (botan_cipher_set_key(cipher, this->key.ptr, this->key.len))
-	{
-		botan_cipher_destroy(cipher);
-		return FALSE;
-	}
-
-	if (assoc.len &&
-		botan_cipher_set_associated_data(cipher, assoc.ptr, assoc.len))
-	{
-		botan_cipher_destroy(cipher);
-		return FALSE;
-	}
-
-	if (botan_cipher_start(cipher, nonce, NONCE_LEN))
-	{
-		botan_cipher_destroy(cipher);
-		return FALSE;
-	}
-
-	if (init_flag == BOTAN_CIPHER_INIT_FLAG_ENCRYPT)
-	{
-		if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
-								out, data.len + this->icv_size, &output_written,
-								data.ptr, data.len, &input_consumed))
-		{
-			botan_cipher_destroy(cipher);
-			return FALSE;
-		}
-	}
-	else if (init_flag == BOTAN_CIPHER_INIT_FLAG_DECRYPT)
-	{
-		if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
-								out, data.len, &output_written, data.ptr,
-								data.len + this->icv_size, &input_consumed))
-		{
-			botan_cipher_destroy(cipher);
-			return FALSE;
-		}
-	}
-
-	botan_cipher_destroy(cipher);
-
-	return TRUE;
-}
-
-METHOD(aead_t, encrypt, bool,
-	private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
-	chunk_t *encrypted)
-{
-	u_char *out;
-
-	out = plain.ptr;
-	if (encrypted)
-	{
-		*encrypted = chunk_alloc(plain.len + this->icv_size);
-		out = encrypted->ptr;
-	}
-	return crypt(this, plain, assoc, iv, out, BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
-}
-
-METHOD(aead_t, decrypt, bool,
-	private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
-	chunk_t *plain)
-{
-	u_char *out;
-
-	if (encrypted.len < this->icv_size)
-	{
-		return FALSE;
-	}
-	encrypted.len -= this->icv_size;
-
-	out = encrypted.ptr;
-	if (plain)
-	{
-		*plain = chunk_alloc(encrypted.len);
-		out = plain->ptr;
-	}
-	return crypt(this, encrypted, assoc, iv, out,
-				 BOTAN_CIPHER_INIT_FLAG_DECRYPT);
-}
-
-METHOD(aead_t, get_block_size, size_t,
-	private_aead_t *this)
-{
-	return 1;
-}
-
-METHOD(aead_t, get_icv_size, size_t,
-	private_aead_t *this)
-{
-	return this->icv_size;
-}
-
-METHOD(aead_t, get_iv_size, size_t,
-	private_aead_t *this)
-{
-	return IV_LEN;
-}
-
-METHOD(aead_t, get_iv_gen, iv_gen_t*,
-	private_aead_t *this)
-{
-	return this->iv_gen;
-}
-
-METHOD(aead_t, get_key_size, size_t,
-	private_aead_t *this)
-{
-	return this->key.len + SALT_LEN;
-}
-
-METHOD(aead_t, set_key, bool,
-	private_aead_t *this, chunk_t key)
-{
-	if (key.len != get_key_size(this))
-	{
-		return FALSE;
-	}
-	memcpy(this->salt, key.ptr + key.len - SALT_LEN, SALT_LEN);
-	memcpy(this->key.ptr, key.ptr, this->key.len);
-	return TRUE;
-}
-
-METHOD(aead_t, destroy, void,
-	private_aead_t *this)
-{
-	chunk_clear(&this->key);
-	this->iv_gen->destroy(this->iv_gen);
-	free(this);
-}
-
-/*
- * Described in header
- */
-aead_t *botan_gcm_create(encryption_algorithm_t algo, size_t key_size,
-						 size_t salt_size)
-{
-	private_aead_t *this;
-
-	INIT(this,
-		.public = {
-			.encrypt = _encrypt,
-			.decrypt = _decrypt,
-			.get_block_size = _get_block_size,
-			.get_icv_size = _get_icv_size,
-			.get_iv_size = _get_iv_size,
-			.get_iv_gen = _get_iv_gen,
-			.get_key_size = _get_key_size,
-			.set_key = _set_key,
-			.destroy = _destroy,
-		},
-	);
-
-	if (salt_size && salt_size != SALT_LEN)
-	{
-		/* currently not supported */
-		free(this);
-		return NULL;
-	}
-
-	switch (algo)
-	{
-		case ENCR_AES_GCM_ICV8:
-			switch (key_size)
-			{
-				case 0:
-					key_size = 16;
-					/* FALL */
-				case 16:
-					this->cipher_name = "AES-128/GCM(8)";
-					break;
-				case 24:
-					this->cipher_name = "AES-192/GCM(8)";
-					break;
-				case 32:
-					this->cipher_name = "AES-256/GCM(8)";
-					break;
-				default:
-					free(this);
-					return NULL;
-			}
-			this->icv_size = 8;
-			break;
-		case ENCR_AES_GCM_ICV12:
-			switch (key_size)
-			{
-				case 0:
-					key_size = 16;
-					/* FALL */
-				case 16:
-					this->cipher_name = "AES-128/GCM(12)";
-					break;
-				case 24:
-					this->cipher_name = "AES-192/GCM(12)";
-					break;
-				case 32:
-					this->cipher_name = "AES-256/GCM(12)";
-					break;
-				default:
-					free(this);
-					return NULL;
-			}
-			this->icv_size = 12;
-			break;
-		case ENCR_AES_GCM_ICV16:
-			switch (key_size)
-			{
-				case 0:
-					key_size = 16;
-					/* FALL */
-				case 16:
-					this->cipher_name = "AES-128/GCM";
-					break;
-				case 24:
-					this->cipher_name = "AES-192/GCM";
-					break;
-				case 32:
-					this->cipher_name = "AES-256/GCM";
-					break;
-				default:
-					free(this);
-					return NULL;
-			}
-			this->icv_size = 16;
-			break;
-		default:
-			free(this);
-			return NULL;
-	}
-
-	this->key = chunk_alloc(key_size);
-	this->iv_gen = iv_gen_seq_create();
-
-	return &this->public;
-}
-
-#endif
-#endif
diff --git a/src/libstrongswan/plugins/botan/botan_gcm.h b/src/libstrongswan/plugins/botan/botan_gcm.h
deleted file mode 100644
index b2053cb4d..000000000
--- a/src/libstrongswan/plugins/botan/botan_gcm.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2018 Atanas Filyanov
- * Rohde & Schwarz Cybersecurity GmbH
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/**
- * Implements the aead_t interface using Botan in GCM mode.
- *
- * @defgroup botan_gcm botan_gcm
- * @{ @ingroup botan_p
- */
-
-#ifndef BOTAN_GCM_H_
-#define BOTAN_GCM_H_
-
-#include <crypto/aead.h>
-
-/**
- * Constructor to create aead_t implementation.
- *
- * @param algo			algorithm to implement
- * @param key_size		key size in bytes
- * @param salt_size		size of implicit salt length
- * @return				aead_t object, NULL if not supported
- */
-aead_t *botan_gcm_create(encryption_algorithm_t algo, size_t key_size,
-						 size_t salt_size);
-
-#endif /** BOTAN_GCM_H_ @}*/
diff --git a/src/libstrongswan/plugins/botan/botan_plugin.c b/src/libstrongswan/plugins/botan/botan_plugin.c
index fd8e5f5a6..f045ba074 100644
--- a/src/libstrongswan/plugins/botan/botan_plugin.c
+++ b/src/libstrongswan/plugins/botan/botan_plugin.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Tobias Brunner
+ * Copyright (C) 2018 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2018 René Korthaus
@@ -36,7 +37,9 @@
 #include "botan_ec_diffie_hellman.h"
 #include "botan_ec_public_key.h"
 #include "botan_ec_private_key.h"
-#include "botan_gcm.h"
+#include "botan_ed_public_key.h"
+#include "botan_ed_private_key.h"
+#include "botan_aead.h"
 #include "botan_util_keys.h"
 #include "botan_x25519.h"
 
@@ -101,6 +104,7 @@ METHOD(plugin_t, get_features, int,
 #endif
 
 		/* crypters */
+#if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_MODE_CBC)
 		PLUGIN_REGISTER(CRYPTER, botan_crypter_create),
 #ifdef BOTAN_HAS_AES
 	#ifdef BOTAN_HAS_MODE_CBC
@@ -108,17 +112,43 @@ METHOD(plugin_t, get_features, int,
 			PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 24),
 			PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 32),
 	#endif
+#endif
+#endif
+
+		/* AEAD */
+#if (defined(BOTAN_HAS_AES) && \
+		(defined(BOTAN_HAS_AEAD_GCM) || defined(BOTAN_HAS_AEAD_CCM))) || \
+	defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
+		PLUGIN_REGISTER(AEAD, botan_aead_create),
+#ifdef BOTAN_HAS_AES
 	#ifdef BOTAN_HAS_AEAD_GCM
-			/* AES GCM */
-			PLUGIN_REGISTER(AEAD, botan_gcm_create),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 16),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 24),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 32),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 16),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 24),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 32),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  16),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  24),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  32),
 	#endif
+	#ifdef BOTAN_HAS_AEAD_CCM
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 16),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 24),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 32),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 16),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 24),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 32),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  16),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  24),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  32),
+	#endif
+#endif
+#ifdef BOTAN_HAS_AEAD_CHACHA20_POLY1305
+			PLUGIN_PROVIDE(AEAD, ENCR_CHACHA20_POLY1305, 32),
 #endif
+#endif
+
 		/* hashers */
 		PLUGIN_REGISTER(HASHER, botan_hasher_create),
 #ifdef BOTAN_HAS_MD5
@@ -135,6 +165,13 @@ METHOD(plugin_t, get_features, int,
 			PLUGIN_PROVIDE(HASHER, HASH_SHA384),
 			PLUGIN_PROVIDE(HASHER, HASH_SHA512),
 #endif
+#ifdef BOTAN_HAS_SHA3
+			PLUGIN_PROVIDE(HASHER, HASH_SHA3_224),
+			PLUGIN_PROVIDE(HASHER, HASH_SHA3_256),
+			PLUGIN_PROVIDE(HASHER, HASH_SHA3_384),
+			PLUGIN_PROVIDE(HASHER, HASH_SHA3_512),
+#endif
+
 		/* prfs */
 #ifdef BOTAN_HAS_HMAC
 		PLUGIN_REGISTER(PRF, botan_hmac_prf_create),
@@ -168,7 +205,8 @@ METHOD(plugin_t, get_features, int,
 #endif /* BOTAN_HAS_HMAC */
 
 		/* generic key loaders */
-#if defined (BOTAN_HAS_RSA) || defined(BOTAN_HAS_ECDSA)
+#if defined (BOTAN_HAS_RSA) || defined(BOTAN_HAS_ECDSA) || \
+	defined(BOTAN_HAS_ED25519)
 		PLUGIN_REGISTER(PUBKEY, botan_public_key_load, TRUE),
 			PLUGIN_PROVIDE(PUBKEY, KEY_ANY),
 #ifdef BOTAN_HAS_RSA
@@ -176,6 +214,9 @@ METHOD(plugin_t, get_features, int,
 #endif
 #ifdef BOTAN_HAS_ECDSA
 			PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA),
+#endif
+#ifdef BOTAN_HAS_ED25519
+			PLUGIN_PROVIDE(PUBKEY, KEY_ED25519),
 #endif
 		PLUGIN_REGISTER(PRIVKEY, botan_private_key_load, TRUE),
 			PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
@@ -185,6 +226,9 @@ METHOD(plugin_t, get_features, int,
 #ifdef BOTAN_HAS_ECDSA
 			PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
 #endif
+#ifdef BOTAN_HAS_ED25519
+			PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519),
+#endif
 #endif
 		/* RSA */
 #ifdef BOTAN_HAS_RSA
@@ -218,6 +262,16 @@ METHOD(plugin_t, get_features, int,
 		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_384),
 		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_512),
 #endif
+#ifdef BOTAN_HAS_SHA3
+		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA3_224),
+		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA3_256),
+		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA3_384),
+		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA3_512),
+		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA3_224),
+		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA3_256),
+		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA3_384),
+		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA3_512),
+#endif
 #endif
 #ifdef BOTAN_HAS_EMSA_PSSR
 		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS),
@@ -272,6 +326,21 @@ METHOD(plugin_t, get_features, int,
 #endif /* BOTAN_HAS_EMSA1 */
 #endif /* BOTAN_HAS_ECDSA */
 
+#ifdef BOTAN_HAS_ED25519
+		/* EdDSA private/public key loading */
+		PLUGIN_REGISTER(PUBKEY, botan_ed_public_key_load, TRUE),
+			PLUGIN_PROVIDE(PUBKEY, KEY_ED25519),
+		PLUGIN_REGISTER(PRIVKEY, botan_ed_private_key_load, TRUE),
+			PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519),
+		PLUGIN_REGISTER(PRIVKEY_GEN, botan_ed_private_key_gen, FALSE),
+			PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ED25519),
+		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ED25519),
+		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ED25519),
+		/* register a pro forma identity hasher, never instantiated */
+		PLUGIN_REGISTER(HASHER, return_null),
+			PLUGIN_PROVIDE(HASHER, HASH_IDENTITY),
+#endif
+
 		/* random numbers */
 #if BOTAN_HAS_SYSTEM_RNG
 #if BOTAN_HAS_HMAC_DRBG
diff --git a/src/libstrongswan/plugins/botan/botan_rsa_private_key.c b/src/libstrongswan/plugins/botan/botan_rsa_private_key.c
index bb723ff95..02820b297 100644
--- a/src/libstrongswan/plugins/botan/botan_rsa_private_key.c
+++ b/src/libstrongswan/plugins/botan/botan_rsa_private_key.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Tobias Brunner
+ * Copyright (C) 2018 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2018 René Korthaus
@@ -84,13 +85,8 @@ bool botan_emsa_pss_identifier(rsa_pss_params_t *params, char *id, size_t len)
 	{
 		return FALSE;
 	}
-
-	if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
-	{
-		return snprintf(id, len, "EMSA-PSS(%s,MGF1,%zd)", hash,
-						params->salt_len) < len;
-	}
-	return snprintf(id, len, "EMSA-PSS(%s,MGF1)", hash) < len;
+	return snprintf(id, len, "EMSA-PSS(%s,MGF1,%zd)", hash,
+					params->salt_len) < len;
 }
 
 /**
@@ -140,6 +136,18 @@ METHOD(private_key_t, sign, bool,
 		case SIGN_RSA_EMSA_PKCS1_SHA2_512:
 			return botan_get_signature(this->key, "EMSA_PKCS1(SHA-512)", data,
 									   signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_224:
+			return botan_get_signature(this->key, "EMSA_PKCS1(SHA-3(224))", data,
+									   signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_256:
+			return botan_get_signature(this->key, "EMSA_PKCS1(SHA-3(256))", data,
+									   signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_384:
+			return botan_get_signature(this->key, "EMSA_PKCS1(SHA-3(384))", data,
+									   signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_512:
+			return botan_get_signature(this->key, "EMSA_PKCS1(SHA-3(512))", data,
+									   signature);
 		case SIGN_RSA_EMSA_PSS:
 			return build_emsa_pss_signature(this, params, data, signature);
 		default:
@@ -617,7 +625,7 @@ botan_rsa_private_key_t *botan_rsa_private_key_load(key_type_t type,
 
 	if (n.ptr && e.ptr && d.ptr)
 	{
-		botan_mp_t n_mp, e_mp, d_mp, p_mp, q_mp;
+		botan_mp_t n_mp, e_mp, d_mp, p_mp = NULL, q_mp = NULL;
 
 		if (!chunk_to_botan_mp(n, &n_mp))
 		{
diff --git a/src/libstrongswan/plugins/botan/botan_rsa_public_key.c b/src/libstrongswan/plugins/botan/botan_rsa_public_key.c
index c6e2e8861..244caa585 100644
--- a/src/libstrongswan/plugins/botan/botan_rsa_public_key.c
+++ b/src/libstrongswan/plugins/botan/botan_rsa_public_key.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Tobias Brunner
+ * Copyright (C) 2018 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2018 René Korthaus
@@ -68,33 +69,6 @@ struct private_botan_rsa_public_key_t {
  */
 bool botan_emsa_pss_identifier(rsa_pss_params_t *params, char *id, size_t len);
 
-/**
- * Verify RSA signature
- */
-static bool verify_rsa_signature(private_botan_rsa_public_key_t *this,
-								 const char* hash_and_padding, chunk_t data,
-								 chunk_t signature)
-{
-	botan_pk_op_verify_t verify_op;
-	bool valid = FALSE;
-
-	if (botan_pk_op_verify_create(&verify_op, this->key, hash_and_padding, 0))
-	{
-		return FALSE;
-	}
-
-	if (botan_pk_op_verify_update(verify_op, data.ptr, data.len))
-	{
-		botan_pk_op_verify_destroy(verify_op);
-		return FALSE;
-	}
-
-	valid =	!botan_pk_op_verify_finish(verify_op, signature.ptr, signature.len);
-
-	botan_pk_op_verify_destroy(verify_op);
-	return valid;
-}
-
 /**
  * Verification of an EMSA PSS signature described in PKCS#1
  */
@@ -109,7 +83,7 @@ static bool verify_emsa_pss_signature(private_botan_rsa_public_key_t *this,
 	{
 		return FALSE;
 	}
-	return verify_rsa_signature(this, hash_and_padding, data, signature);
+	return botan_verify_signature(this->key, hash_and_padding, data, signature);
 }
 
 METHOD(public_key_t, get_type, key_type_t,
@@ -125,23 +99,35 @@ METHOD(public_key_t, verify, bool,
 	switch (scheme)
 	{
 		case SIGN_RSA_EMSA_PKCS1_NULL:
-			return verify_rsa_signature(this, "EMSA_PKCS1(Raw)", data,
-										signature);
+			return botan_verify_signature(this->key, "EMSA_PKCS1(Raw)", data,
+										  signature);
 		case SIGN_RSA_EMSA_PKCS1_SHA1:
-			return verify_rsa_signature(this, "EMSA_PKCS1(SHA-1)", data,
-										signature);
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-1)", data,
+										  signature);
 		case SIGN_RSA_EMSA_PKCS1_SHA2_224:
-			return verify_rsa_signature(this, "EMSA_PKCS1(SHA-224)",
-										data, signature);
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-224)",
+										  data, signature);
 		case SIGN_RSA_EMSA_PKCS1_SHA2_256:
-			return verify_rsa_signature(this, "EMSA_PKCS1(SHA-256)",
-										data, signature);
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-256)",
+										  data, signature);
 		case SIGN_RSA_EMSA_PKCS1_SHA2_384:
-			return verify_rsa_signature(this, "EMSA_PKCS1(SHA-384)",
-										data, signature);
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-384)",
+										  data, signature);
 		case SIGN_RSA_EMSA_PKCS1_SHA2_512:
-			return verify_rsa_signature(this, "EMSA_PKCS1(SHA-512)",
-										data, signature);
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-512)",
+										  data, signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_224:
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-3(224)",
+										  data, signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_256:
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-3(256))",
+										  data, signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_384:
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-3(384))",
+										  data, signature);
+		case SIGN_RSA_EMSA_PKCS1_SHA3_512:
+			return botan_verify_signature(this->key, "EMSA_PKCS1(SHA-3(512))",
+										  data, signature);
 		case SIGN_RSA_EMSA_PSS:
 			return verify_emsa_pss_signature(this, params, data, signature);
 		default:
diff --git a/src/libstrongswan/plugins/botan/botan_util.c b/src/libstrongswan/plugins/botan/botan_util.c
index 5e18405d7..f5728e43e 100644
--- a/src/libstrongswan/plugins/botan/botan_util.c
+++ b/src/libstrongswan/plugins/botan/botan_util.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Tobias Brunner
+ * Copyright (C) 2018 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2018 René Korthaus
@@ -67,6 +68,14 @@ const char *botan_get_hash(hash_algorithm_t hash)
 			return "SHA-384";
 		case HASH_SHA512:
 			return "SHA-512";
+		case HASH_SHA3_224:
+			return "SHA-3(224)";
+		case HASH_SHA3_256:
+			return "SHA-3(256)";
+		case HASH_SHA3_384:
+			return "SHA-3(384)";
+		case HASH_SHA3_512:
+			return "SHA-3(512)";
 		default:
 			return NULL;
 	}
@@ -249,6 +258,32 @@ bool botan_get_signature(botan_privkey_t key, const char *scheme,
 	return TRUE;
 }
 
+/*
+ * Described in header
+ */
+bool botan_verify_signature(botan_pubkey_t key, const char *scheme,
+							chunk_t data, chunk_t signature)
+{
+	botan_pk_op_verify_t verify_op;
+	bool valid = FALSE;
+
+	if (botan_pk_op_verify_create(&verify_op, key, scheme, 0))
+	{
+		return FALSE;
+	}
+
+	if (botan_pk_op_verify_update(verify_op, data.ptr, data.len))
+	{
+		botan_pk_op_verify_destroy(verify_op);
+		return FALSE;
+	}
+
+	valid =	!botan_pk_op_verify_finish(verify_op, signature.ptr, signature.len);
+
+	botan_pk_op_verify_destroy(verify_op);
+	return valid;
+}
+
 /*
  * Described in header
  */
diff --git a/src/libstrongswan/plugins/botan/botan_util.h b/src/libstrongswan/plugins/botan/botan_util.h
index 08830356e..7fb74ec5d 100644
--- a/src/libstrongswan/plugins/botan/botan_util.h
+++ b/src/libstrongswan/plugins/botan/botan_util.h
@@ -100,6 +100,18 @@ bool botan_get_fingerprint(botan_pubkey_t pubkey, void *cache,
 bool botan_get_signature(botan_privkey_t key, const char *scheme,
 						 chunk_t data, chunk_t *signature);
 
+/**
+ * Verify the given signature using the provided data and key with the specified
+ * signature scheme (hash/padding).
+ *
+ * @param key		private key object
+ * @param scheme	hash/padding algorithm
+ * @param data		signed data
+ * @param signature	signature to verify
+ */
+bool botan_verify_signature(botan_pubkey_t key, const char* scheme,
+							chunk_t data, chunk_t signature);
+
 /**
  * Do the Diffie-Hellman key derivation using the given private key and public
  * value.
diff --git a/src/libstrongswan/plugins/botan/botan_util_keys.c b/src/libstrongswan/plugins/botan/botan_util_keys.c
index 176c2caf9..dc4031491 100644
--- a/src/libstrongswan/plugins/botan/botan_util_keys.c
+++ b/src/libstrongswan/plugins/botan/botan_util_keys.c
@@ -24,6 +24,8 @@
 #include "botan_util_keys.h"
 #include "botan_ec_public_key.h"
 #include "botan_ec_private_key.h"
+#include "botan_ed_public_key.h"
+#include "botan_ed_private_key.h"
 #include "botan_rsa_public_key.h"
 #include "botan_rsa_private_key.h"
 
@@ -104,15 +106,27 @@ public_key_t *botan_public_key_load(key_type_t type, va_list args)
 		return NULL;
 	}
 
+#ifdef BOTAN_HAS_RSA
 	if (streq(name, "RSA") && (type == KEY_ANY || type == KEY_RSA))
 	{
 		this = (public_key_t*)botan_rsa_public_key_adopt(pubkey);
 	}
-	else if (streq(name, "ECDSA") && (type == KEY_ANY || type == KEY_ECDSA))
+	else
+#endif
+#ifdef BOTAN_HAS_ECDSA
+	if (streq(name, "ECDSA") && (type == KEY_ANY || type == KEY_ECDSA))
 	{
 		this = (public_key_t*)botan_ec_public_key_adopt(pubkey);
 	}
 	else
+#endif
+#ifdef BOTAN_HAS_ED25519
+	if (streq(name, "Ed25519") && (type == KEY_ANY || type == KEY_ED25519))
+	{
+		this = botan_ed_public_key_adopt(pubkey);
+	}
+	else
+#endif
 	{
 		botan_pubkey_destroy(pubkey);
 	}
@@ -120,6 +134,7 @@ public_key_t *botan_public_key_load(key_type_t type, va_list args)
 	return this;
 }
 
+#ifdef BOTAN_HAS_ECDSA
 /**
  * Determine the curve OID from a PKCS#8 structure
  */
@@ -139,6 +154,7 @@ static int determine_ec_oid(chunk_t pkcs8)
 	}
 	return oid;
 }
+#endif
 
 /*
  * Described in header
@@ -151,7 +167,6 @@ private_key_t *botan_private_key_load(key_type_t type, va_list args)
 	chunk_t blob = chunk_empty;
 	botan_rng_t rng;
 	char *name;
-	int oid;
 
 	while (TRUE)
 	{
@@ -188,20 +203,35 @@ private_key_t *botan_private_key_load(key_type_t type, va_list args)
 	botan_pubkey_destroy(pubkey);
 	if (!name)
 	{
+		botan_privkey_destroy(key);
 		return NULL;
 	}
+
+#ifdef BOTAN_HAS_RSA
 	if (streq(name, "RSA") && (type == KEY_ANY || type == KEY_RSA))
 	{
 		this = (private_key_t*)botan_rsa_private_key_adopt(key);
 	}
-	else if (streq(name, "ECDSA") && (type == KEY_ANY || type == KEY_ECDSA))
+	else
+#endif
+#ifdef BOTAN_HAS_ECDSA
+	if (streq(name, "ECDSA") && (type == KEY_ANY || type == KEY_ECDSA))
 	{
-		oid = determine_ec_oid(blob);
+		int oid = determine_ec_oid(blob);
 		if (oid != OID_UNKNOWN)
 		{
 			this = (private_key_t*)botan_ec_private_key_adopt(key, oid);
 		}
 	}
+	else
+#endif
+#ifdef BOTAN_HAS_ED25519
+	if (streq(name, "Ed25519") && (type == KEY_ANY || type == KEY_ED25519))
+	{
+		this = botan_ed_private_key_adopt(key);
+	}
+#endif
+
 	if (!this)
 	{
 		botan_privkey_destroy(key);
diff --git a/src/libstrongswan/plugins/curve25519/curve25519_public_key.c b/src/libstrongswan/plugins/curve25519/curve25519_public_key.c
index 1d4dec565..dfc1df4d0 100644
--- a/src/libstrongswan/plugins/curve25519/curve25519_public_key.c
+++ b/src/libstrongswan/plugins/curve25519/curve25519_public_key.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2018 Tobias Brunner
  * Copyright (C) 2016 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -48,6 +49,13 @@ METHOD(public_key_t, get_type, key_type_t,
 	return KEY_ED25519;
 }
 
+/* L = 2^252+27742317777372353535851937790883648493 in little-endian form */
+static chunk_t curve25519_order = chunk_from_chars(
+								0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+								0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10);
+
 METHOD(public_key_t, verify, bool,
 	private_curve25519_public_key_t *this, signature_scheme_t scheme,
 	void *params, chunk_t data, chunk_t signature)
@@ -93,6 +101,20 @@ METHOD(public_key_t, verify, bool,
 	{
 		return FALSE;
 	}
+	/* make sure 0 <= s < L, as per RFC 8032, section 5.1.7 to prevent signature
+	 * malleability.  Due to the three-bit check above (forces s < 2^253) there
+	 * is not that much room, but adding L once works with most signatures */
+	for (i = 31; ; i--)
+	{
+		if (sig[i+32] < curve25519_order.ptr[i])
+		{
+			break;
+		}
+		else if (sig[i+32] > curve25519_order.ptr[i] || i == 0)
+		{
+			return FALSE;
+		}
+	}
 
 	hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512);
 	if (!hasher)
@@ -199,6 +221,52 @@ static const asn1Object_t pubkeyObjects[] = {
 #define ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM	1
 #define ED25519_SUBJECT_PUBLIC_KEY				2
 
+/**
+ * Parse the ASN.1-encoded subjectPublicKeyInfo
+ */
+static bool parse_public_key_info(private_curve25519_public_key_t *this,
+								  chunk_t blob)
+{
+	asn1_parser_t *parser;
+	chunk_t object;
+	bool success = FALSE;
+	int objectID, oid;
+
+	parser = asn1_parser_create(pubkeyObjects, blob);
+
+	while (parser->iterate(parser, &objectID, &object))
+	{
+		switch (objectID)
+		{
+			case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM:
+			{
+				oid = asn1_parse_algorithmIdentifier(object,
+										parser->get_level(parser) + 1, NULL);
+				if (oid != OID_ED25519)
+				{
+					goto end;
+				}
+				break;
+			}
+			case ED25519_SUBJECT_PUBLIC_KEY:
+			{
+				/* encoded as an ASN1 BIT STRING */
+				if (object.len != 1 + ED25519_KEY_LEN)
+				{
+					goto end;
+				}
+				this->pubkey = chunk_clone(chunk_skip(object, 1));
+				break;
+			}
+		}
+	}
+	success = parser->success(parser);
+
+end:
+	parser->destroy(parser);
+	return success;
+}
+
 /**
  * See header.
  */
@@ -206,16 +274,16 @@ curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
 													va_list args)
 {
 	private_curve25519_public_key_t *this;
-	chunk_t blob = chunk_empty, object;
-	asn1_parser_t *parser;
-	bool success = FALSE;
-	int objectID, oid;
+	chunk_t asn1 = chunk_empty, blob = chunk_empty;
 
 	while (TRUE)
 	{
 		switch (va_arg(args, builder_part_t))
 		{
 			case BUILD_BLOB_ASN1_DER:
+				asn1 = va_arg(args, chunk_t);
+				continue;
+			case BUILD_EDDSA_PUB:
 				blob = va_arg(args, chunk_t);
 				continue;
 			case BUILD_END:
@@ -244,39 +312,11 @@ curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
 		.ref = 1,
 	);
 
-	parser = asn1_parser_create(pubkeyObjects, blob);
-
-	while (parser->iterate(parser, &objectID, &object))
+	if (blob.len == ED25519_KEY_LEN)
 	{
-		switch (objectID)
-		{
-			case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM:
-			{
-				oid = asn1_parse_algorithmIdentifier(object,
-										parser->get_level(parser) + 1, NULL);
-				if (oid != OID_ED25519)
-				{
-					goto end;
-				}
-				break;
-			}
-			case ED25519_SUBJECT_PUBLIC_KEY:
-			{
-				/* encoded as an ASN1 BIT STRING */
-				if (object.len != 1 + ED25519_KEY_LEN)
-				{
-					goto end;
-				}
-				this->pubkey = chunk_clone(chunk_skip(object, 1));
-				break;
-			}
-		}
+		this->pubkey = chunk_clone(blob);
 	}
-	success = parser->success(parser);
-
-end:
-	parser->destroy(parser);
-	if (!success)
+	else if (!asn1.len || !parse_public_key_info(this, asn1))
 	{
 		destroy(this);
 		return NULL;
diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c b/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c
index 45fba242b..6946e4576 100644
--- a/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c
+++ b/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c
@@ -43,10 +43,12 @@ struct private_gcrypt_plugin_t {
 	gcrypt_plugin_t public;
 };
 
+#if GCRYPT_VERSION_NUMBER < 0x010600
 /**
  * Define gcrypt multi-threading callbacks as gcry_threads_pthread
  */
 GCRY_THREAD_OPTION_PTHREAD_IMPL;
+#endif
 
 METHOD(plugin_t, get_name, char*,
 	private_gcrypt_plugin_t *this)
@@ -163,7 +165,9 @@ plugin_t *gcrypt_plugin_create()
 {
 	private_gcrypt_plugin_t *this;
 
+#if GCRYPT_VERSION_NUMBER < 0x010600
 	gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+#endif
 
 	if (!gcry_check_version(GCRYPT_VERSION))
 	{
diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c
index c06f43348..394b87c27 100644
--- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c
+++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c
@@ -187,11 +187,7 @@ static bool sign_pkcs1(private_gcrypt_rsa_private_key_t *this,
 		}
 		else
 		{
-			u_int slen = hasher_hash_size(hash_algorithm);
-			if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
-			{
-				slen = pss->salt_len;
-			}
+			u_int slen = pss->salt_len;
 			err = gcry_sexp_build(&in, NULL,
 							"(data(flags pss)(salt-length %u)(hash %s %b))",
 							slen, hash_name, hash.len, hash.ptr);
diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c
index 9e2ac1287..bbfa5e298 100644
--- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c
+++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c
@@ -139,11 +139,7 @@ static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
 
 	if (pss)
 	{
-		u_int slen = hasher_hash_size(algorithm);
-		if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
-		{
-			slen = pss->salt_len;
-		}
+		u_int slen = pss->salt_len;
 		err = gcry_sexp_build(&in, NULL,
 							  "(data(flags pss)(salt-length %u)(hash %s %b))",
 							  slen, hash_name, hash.len, hash.ptr);
diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
index a255a40ab..2d2d5c6fb 100644
--- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
+++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
@@ -393,15 +393,11 @@ static bool build_emsa_pss_signature(private_gmp_rsa_private_key_t *this,
 		goto error;
 	}
 
-	salt.len = hash.len;
+	salt.len = params->salt_len;
 	if (params->salt.len)
 	{
 		salt = params->salt;
 	}
-	else if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
-	{
-		salt.len = params->salt_len;
-	}
 	if (emlen < (hash.len + salt.len + 2))
 	{	/* too long */
 		goto error;
diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
index 9b5ee67fa..f9bd1d314 100644
--- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
+++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
@@ -205,12 +205,7 @@ static bool verify_emsa_pss_signature(private_gmp_rsa_public_key_t *this,
 	{
 		goto error;
 	}
-	/* determine salt length */
-	salt.len = hash.len;
-	if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
-	{
-		salt.len = params->salt_len;
-	}
+	salt.len = params->salt_len;
 	/* verify general structure of EM */
 	maskbits = (8 * em.len) - embits;
 	if (em.len < (hash.len + salt.len + 2) || em.ptr[em.len-1] != 0xbc ||
diff --git a/src/libstrongswan/plugins/mysql/mysql_database.c b/src/libstrongswan/plugins/mysql/mysql_database.c
index d7e35d9fd..90f8185b0 100644
--- a/src/libstrongswan/plugins/mysql/mysql_database.c
+++ b/src/libstrongswan/plugins/mysql/mysql_database.c
@@ -131,9 +131,13 @@ typedef struct {
  */
 static void conn_release(private_mysql_database_t *this, conn_t *conn)
 {
-	this->mutex->lock(this->mutex);
-	conn->in_use = FALSE;
-	this->mutex->unlock(this->mutex);
+	/* do not release the connection while transactions are using it */
+	if (!this->transaction->get(this->transaction))
+	{
+		this->mutex->lock(this->mutex);
+		conn->in_use = FALSE;
+		this->mutex->unlock(this->mutex);
+	}
 }
 
 /**
diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am
index 9287f788a..d484092e7 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.am
+++ b/src/libstrongswan/plugins/openssl/Makefile.am
@@ -29,7 +29,10 @@ libstrongswan_openssl_la_SOURCES = \
 	openssl_pkcs12.c openssl_pkcs12.h \
 	openssl_rng.c openssl_rng.h \
 	openssl_hmac.c openssl_hmac.h \
-	openssl_gcm.c openssl_gcm.h
+	openssl_gcm.c openssl_gcm.h \
+	openssl_x_diffie_hellman.c openssl_x_diffie_hellman.h \
+	openssl_ed_private_key.c openssl_ed_private_key.h \
+	openssl_ed_public_key.c openssl_ed_public_key.h
 
 libstrongswan_openssl_la_LDFLAGS = -module -avoid-version
 libstrongswan_openssl_la_LIBADD  = $(OPENSSL_LIB)
diff --git a/src/libstrongswan/plugins/openssl/Makefile.in b/src/libstrongswan/plugins/openssl/Makefile.in
index 79be2e670..da04d17cf 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.in
+++ b/src/libstrongswan/plugins/openssl/Makefile.in
@@ -145,7 +145,8 @@ am_libstrongswan_openssl_la_OBJECTS = openssl_plugin.lo \
 	openssl_ec_diffie_hellman.lo openssl_ec_private_key.lo \
 	openssl_ec_public_key.lo openssl_x509.lo openssl_crl.lo \
 	openssl_pkcs7.lo openssl_pkcs12.lo openssl_rng.lo \
-	openssl_hmac.lo openssl_gcm.lo
+	openssl_hmac.lo openssl_gcm.lo openssl_x_diffie_hellman.lo \
+	openssl_ed_private_key.lo openssl_ed_public_key.lo
 libstrongswan_openssl_la_OBJECTS =  \
 	$(am_libstrongswan_openssl_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -487,7 +488,10 @@ libstrongswan_openssl_la_SOURCES = \
 	openssl_pkcs12.c openssl_pkcs12.h \
 	openssl_rng.c openssl_rng.h \
 	openssl_hmac.c openssl_hmac.h \
-	openssl_gcm.c openssl_gcm.h
+	openssl_gcm.c openssl_gcm.h \
+	openssl_x_diffie_hellman.c openssl_x_diffie_hellman.h \
+	openssl_ed_private_key.c openssl_ed_private_key.h \
+	openssl_ed_public_key.c openssl_ed_public_key.h
 
 libstrongswan_openssl_la_LDFLAGS = -module -avoid-version
 libstrongswan_openssl_la_LIBADD = $(OPENSSL_LIB)
@@ -586,6 +590,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ec_diffie_hellman.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ec_private_key.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ec_public_key.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ed_private_key.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ed_public_key.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_gcm.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_hasher.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_hmac.Plo@am__quote@
@@ -598,6 +604,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_sha1_prf.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_util.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_x509.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_x_diffie_hellman.Plo@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
diff --git a/src/libstrongswan/plugins/openssl/openssl_crl.c b/src/libstrongswan/plugins/openssl/openssl_crl.c
index bb5f20dcf..3e7490dc6 100644
--- a/src/libstrongswan/plugins/openssl/openssl_crl.c
+++ b/src/libstrongswan/plugins/openssl/openssl_crl.c
@@ -57,6 +57,9 @@ static inline void X509_CRL_get0_signature(const X509_CRL *crl, ASN1_BIT_STRING
 #define X509_REVOKED_get0_serialNumber(r) ({ (r)->serialNumber; })
 #define X509_REVOKED_get0_revocationDate(r) ({ (r)->revocationDate; })
 #define X509_CRL_get0_extensions(c) ({ (c)->crl->extensions; })
+#define ASN1_STRING_get0_data(a) ASN1_STRING_data(a)
+#define X509_CRL_get0_lastUpdate(c) X509_CRL_get_lastUpdate(c)
+#define X509_CRL_get0_nextUpdate(c) X509_CRL_get_nextUpdate(c)
 #endif
 
 typedef struct private_openssl_crl_t private_openssl_crl_t;
@@ -193,7 +196,7 @@ METHOD(enumerator_t, crl_enumerate, bool,
 				if (ASN1_STRING_type(crlrsn) == V_ASN1_ENUMERATED &&
 					ASN1_STRING_length(crlrsn) == 1)
 				{
-					*reason = *ASN1_STRING_data(crlrsn);
+					*reason = *ASN1_STRING_get0_data(crlrsn);
 				}
 				ASN1_STRING_free(crlrsn);
 			}
@@ -288,7 +291,11 @@ METHOD(certificate_t, issued_by, bool,
 	chunk_t fingerprint, tbs;
 	public_key_t *key;
 	x509_t *x509;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	const ASN1_BIT_STRING *sig;
+#else
 	ASN1_BIT_STRING *sig;
+#endif
 	bool valid;
 
 	if (issuer->get_type(issuer) != CERT_X509)
@@ -509,7 +516,7 @@ static bool parse_extensions(private_openssl_crl_t *this)
 	bool ok;
 	int i, num;
 	X509_EXTENSION *ext;
-	STACK_OF(X509_EXTENSION) *extensions;
+	const STACK_OF(X509_EXTENSION) *extensions;
 
 	extensions = X509_CRL_get0_extensions(this->crl);
 	if (extensions)
@@ -564,7 +571,11 @@ static bool parse_crl(private_openssl_crl_t *this)
 {
 	const unsigned char *ptr = this->encoding.ptr;
 	chunk_t sig_scheme;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	const X509_ALGOR *alg;
+#else
 	X509_ALGOR *alg;
+#endif
 
 	this->crl = d2i_X509_CRL(NULL, &ptr, this->encoding.len);
 	if (!this->crl)
@@ -573,7 +584,7 @@ static bool parse_crl(private_openssl_crl_t *this)
 	}
 
 	X509_CRL_get0_signature(this->crl, NULL, &alg);
-	sig_scheme = openssl_i2chunk(X509_ALGOR, alg);
+	sig_scheme = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg);
 	INIT(this->scheme);
 	if (!signature_params_parse(sig_scheme, 0, this->scheme))
 	{
@@ -588,8 +599,8 @@ static bool parse_crl(private_openssl_crl_t *this)
 	{
 		return FALSE;
 	}
-	this->thisUpdate = openssl_asn1_to_time(X509_CRL_get_lastUpdate(this->crl));
-	this->nextUpdate = openssl_asn1_to_time(X509_CRL_get_nextUpdate(this->crl));
+	this->thisUpdate = openssl_asn1_to_time(X509_CRL_get0_lastUpdate(this->crl));
+	this->nextUpdate = openssl_asn1_to_time(X509_CRL_get0_nextUpdate(this->crl));
 
 	return parse_extensions(this);
 }
diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.c
new file mode 100644
index 000000000..b5bc9b868
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 <openssl/evp.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
+
+#include "openssl_ed_private_key.h"
+
+#include <utils/debug.h>
+
+typedef struct private_private_key_t private_private_key_t;
+
+/**
+ * Private data
+ */
+struct private_private_key_t {
+
+	/**
+	 * Public interface
+	 */
+	private_key_t public;
+
+	/**
+	 * Key object
+	 */
+	EVP_PKEY *key;
+
+	/**
+	 * Key type
+	 */
+	key_type_t type;
+
+	/**
+	 * TRUE if the key is from an OpenSSL ENGINE and might not be readable
+	 */
+	bool engine;
+
+	/**
+	 * reference count
+	 */
+	refcount_t ref;
+};
+
+/**
+ * We can't include asn1.h, declare function prototype directly
+ */
+int asn1_unwrap(chunk_t*, chunk_t*);
+
+/* from ed public key */
+int openssl_ed_key_type(key_type_t type);
+int openssl_ed_keysize(key_type_t type);
+bool openssl_ed_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp);
+
+METHOD(private_key_t, sign, bool,
+	private_private_key_t *this, signature_scheme_t scheme,
+	void *params, chunk_t data, chunk_t *signature)
+{
+	EVP_MD_CTX *ctx;
+	bool success = FALSE;
+
+	if ((this->type == KEY_ED25519 && scheme != SIGN_ED25519) ||
+		(this->type == KEY_ED448 && scheme != SIGN_ED448))
+	{
+		DBG1(DBG_LIB, "signature scheme %N not supported by %N key",
+			 signature_scheme_names, scheme, key_type_names, this->type);
+		return FALSE;
+	}
+
+	ctx = EVP_MD_CTX_new();
+	if (!ctx ||
+		EVP_DigestSignInit(ctx, NULL, NULL, NULL, this->key) <= 0)
+	{
+		goto error;
+	}
+
+	if (EVP_DigestSign(ctx, NULL, &signature->len, data.ptr, data.len) <= 0)
+	{
+		goto error;
+	}
+
+	*signature = chunk_alloc(signature->len);
+
+	if (EVP_DigestSign(ctx, signature->ptr, &signature->len,
+					   data.ptr, data.len) <= 0)
+	{
+		goto error;
+	}
+
+	success = TRUE;
+
+error:
+	EVP_MD_CTX_free(ctx);
+	return success;
+}
+
+METHOD(private_key_t, decrypt, bool,
+	private_private_key_t *this, encryption_scheme_t scheme,
+	chunk_t crypto, chunk_t *plain)
+{
+	DBG1(DBG_LIB, "EdDSA private key decryption not implemented");
+	return FALSE;
+}
+
+METHOD(private_key_t, get_keysize, int,
+	private_private_key_t *this)
+{
+	return openssl_ed_keysize(this->type);
+}
+
+METHOD(private_key_t, get_type, key_type_t,
+	private_private_key_t *this)
+{
+	return this->type;
+}
+
+METHOD(private_key_t, get_public_key, public_key_t*,
+	private_private_key_t *this)
+{
+	public_key_t *public;
+	chunk_t key;
+
+	if (!EVP_PKEY_get_raw_public_key(this->key, NULL, &key.len))
+	{
+		return FALSE;
+	}
+	key = chunk_alloca(key.len);
+	if (!EVP_PKEY_get_raw_public_key(this->key, key.ptr, &key.len))
+	{
+		return FALSE;
+	}
+	public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, this->type,
+								BUILD_EDDSA_PUB, key, BUILD_END);
+	return public;
+}
+
+METHOD(private_key_t, get_fingerprint, bool,
+	private_private_key_t *this, cred_encoding_type_t type,
+	chunk_t *fingerprint)
+{
+	return openssl_ed_fingerprint(this->key, type, fingerprint);
+}
+
+METHOD(private_key_t, get_encoding, bool,
+	private_private_key_t *this, cred_encoding_type_t type, chunk_t *encoding)
+{
+	u_char *p;
+
+	if (this->engine)
+	{
+		return FALSE;
+	}
+
+	switch (type)
+	{
+		case PRIVKEY_ASN1_DER:
+		case PRIVKEY_PEM:
+		{
+			bool success = TRUE;
+
+			*encoding = chunk_alloc(i2d_PrivateKey(this->key, NULL));
+			p = encoding->ptr;
+			i2d_PrivateKey(this->key, &p);
+
+			if (type == PRIVKEY_PEM)
+			{
+				chunk_t asn1_encoding = *encoding;
+
+				success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM,
+								NULL, encoding, CRED_PART_EDDSA_PRIV_ASN1_DER,
+								asn1_encoding, CRED_PART_END);
+				chunk_clear(&asn1_encoding);
+			}
+			return success;
+		}
+		default:
+			return FALSE;
+	}
+}
+
+METHOD(private_key_t, get_ref, private_key_t*,
+	private_private_key_t *this)
+{
+	ref_get(&this->ref);
+	return &this->public;
+}
+
+METHOD(private_key_t, destroy, void,
+	private_private_key_t *this)
+{
+	if (ref_put(&this->ref))
+	{
+		lib->encoding->clear_cache(lib->encoding, this->key);
+		EVP_PKEY_free(this->key);
+		free(this);
+	}
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_private_key_t *create_internal(key_type_t type, EVP_PKEY *key)
+{
+	private_private_key_t *this;
+
+	INIT(this,
+		.public = {
+			.get_type = _get_type,
+			.sign = _sign,
+			.decrypt = _decrypt,
+			.get_keysize = _get_keysize,
+			.get_public_key = _get_public_key,
+			.equals = private_key_equals,
+			.belongs_to = private_key_belongs_to,
+			.get_fingerprint = _get_fingerprint,
+			.has_fingerprint = private_key_has_fingerprint,
+			.get_encoding = _get_encoding,
+			.get_ref = _get_ref,
+			.destroy = _destroy,
+		},
+		.type = type,
+		.key = key,
+		.ref = 1,
+	);
+
+	return this;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *openssl_ed_private_key_create(EVP_PKEY *key, bool engine)
+{
+	private_private_key_t *this;
+	key_type_t type;
+
+	switch (EVP_PKEY_base_id(key))
+	{
+		case EVP_PKEY_X25519:
+			type = KEY_ED25519;
+			break;
+		case EVP_PKEY_X448:
+			type = KEY_ED448;
+			break;
+		default:
+			EVP_PKEY_free(key);
+			return NULL;
+	}
+
+	this = create_internal(type, key);
+	this->engine = engine;
+	return &this->public;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *openssl_ed_private_key_gen(key_type_t type, va_list args)
+{
+	private_private_key_t *this;
+	EVP_PKEY_CTX *ctx;
+	EVP_PKEY *key = NULL;
+
+	while (TRUE)
+	{
+		switch (va_arg(args, builder_part_t))
+		{
+			case BUILD_KEY_SIZE:
+				/* just ignore the key size */
+				va_arg(args, u_int);
+				continue;
+			case BUILD_END:
+				break;
+			default:
+				return NULL;
+		}
+		break;
+	}
+
+	ctx = EVP_PKEY_CTX_new_id(openssl_ed_key_type(type), NULL);
+	if (!ctx ||
+		EVP_PKEY_keygen_init(ctx) <= 0 ||
+		EVP_PKEY_keygen(ctx, &key) <= 0)
+	{
+		DBG1(DBG_LIB, "generating %N key failed", key_type_names, type);
+		EVP_PKEY_CTX_free(ctx);
+		return NULL;
+	}
+	EVP_PKEY_CTX_free(ctx);
+
+	this = create_internal(type, key);
+	return &this->public;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *openssl_ed_private_key_load(key_type_t type, va_list args)
+{
+	private_private_key_t *this;
+	chunk_t blob = chunk_empty, priv = chunk_empty;
+	EVP_PKEY *key = NULL;
+
+	while (TRUE)
+	{
+		switch (va_arg(args, builder_part_t))
+		{
+			case BUILD_BLOB_ASN1_DER:
+				blob = va_arg(args, chunk_t);
+				continue;
+			case BUILD_EDDSA_PRIV_ASN1_DER:
+				priv = va_arg(args, chunk_t);
+				continue;
+			case BUILD_END:
+				break;
+			default:
+				return NULL;
+		}
+		break;
+	}
+
+	if (priv.len)
+	{
+		/* unwrap octet string */
+		if (asn1_unwrap(&priv, &priv) == 0x04 && priv.len)
+		{
+			key = EVP_PKEY_new_raw_private_key(openssl_ed_key_type(type), NULL,
+											   priv.ptr, priv.len);
+		}
+	}
+	else if (blob.len)
+	{
+		key = d2i_PrivateKey(openssl_ed_key_type(type), NULL,
+							 (const u_char**)&blob.ptr, blob.len);
+	}
+	if (!key)
+	{
+		return NULL;
+	}
+	this = create_internal(type, key);
+	return &this->public;
+}
+
+#endif /* OPENSSL_NO_ECDSA */
diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_private_key.h b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.h
new file mode 100644
index 000000000..ce9071348
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 openssl_ed_private_key openssl_ed_private_key
+ * @{ @ingroup openssl_p
+ */
+
+#ifndef OPENSSL_ED_PRIVATE_KEY_H_
+#define OPENSSL_ED_PRIVATE_KEY_H_
+
+#include <openssl/evp.h>
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+/**
+ * Generate an EdDSA private key using OpenSSL.
+ *
+ * @param type		type of the key, must be KEY_ED25519 or KEY_ED448
+ * @param args		builder_part_t argument list
+ * @return 			generated key, NULL on failure
+ */
+private_key_t *openssl_ed_private_key_gen(key_type_t type, va_list args);
+
+/**
+ * Load an EdDSA private key using OpenSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type		type of the key, must be KEY_ED25519 or KEY_ED448
+ * @param args		builder_part_t argument list
+ * @return 			loaded key, NULL on failure
+ */
+private_key_t *openssl_ed_private_key_load(key_type_t type, va_list args);
+
+/**
+ * Wrap an EVP_PKEY object of type EVP_PKEY_ED25519/448
+ *
+ * @param key		EVP_PKEY object (adopted)
+ * @param engine	whether the key was loaded via an engine
+ * @return 			loaded key, NULL on failure
+ */
+private_key_t *openssl_ed_private_key_create(EVP_PKEY *key, bool engine);
+
+#endif /** OPENSSL_ED_PRIVATE_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.c
new file mode 100644
index 000000000..2daddc57e
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 <openssl/evp.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
+
+#include <openssl/x509.h>
+
+#include "openssl_ed_public_key.h"
+
+#include <utils/debug.h>
+
+typedef struct private_public_key_t private_public_key_t;
+
+/**
+ * Private data
+ */
+struct private_public_key_t {
+
+	/**
+	 * Public interface
+	 */
+	public_key_t public;
+
+	/**
+	 * Key object
+	 */
+	EVP_PKEY *key;
+
+	/**
+	 * Key type
+	 */
+	key_type_t type;
+
+	/**
+	 * Reference counter
+	 */
+	refcount_t ref;
+};
+
+/**
+ * Map a key type to an EVP key type
+ */
+int openssl_ed_key_type(key_type_t type)
+{
+	switch (type)
+	{
+		case KEY_ED25519:
+			return EVP_PKEY_ED25519;
+		case KEY_ED448:
+			return EVP_PKEY_ED448;
+		default:
+			return 0;
+	}
+}
+
+/**
+ * Map a key type to a key size
+ */
+int openssl_ed_keysize(key_type_t type)
+{
+	switch (type)
+	{
+		case KEY_ED25519:
+			return 32 * 8;
+		case KEY_ED448:
+			return 57 * 8;
+		default:
+			return 0;
+	}
+}
+
+METHOD(public_key_t, get_type, key_type_t,
+	private_public_key_t *this)
+{
+	return this->type;
+}
+
+METHOD(public_key_t, verify, bool,
+	private_public_key_t *this, signature_scheme_t scheme,
+	void *params, chunk_t data, chunk_t signature)
+{
+	EVP_MD_CTX *ctx;
+
+	if ((this->type == KEY_ED25519 && scheme != SIGN_ED25519) ||
+		(this->type == KEY_ED448 && scheme != SIGN_ED448))
+	{
+		DBG1(DBG_LIB, "signature scheme %N not supported by %N key",
+			 signature_scheme_names, scheme, key_type_names, this->type);
+		return FALSE;
+	}
+
+	ctx = EVP_MD_CTX_new();
+	if (!ctx ||
+		EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, this->key) <= 0 ||
+		EVP_DigestVerify(ctx, signature.ptr, signature.len,
+						 data.ptr, data.len) <= 0)
+	{
+		EVP_MD_CTX_free(ctx);
+		return FALSE;
+	}
+	EVP_MD_CTX_free(ctx);
+	return TRUE;
+}
+
+METHOD(public_key_t, encrypt, bool,
+	private_public_key_t *this, encryption_scheme_t scheme,
+	chunk_t crypto, chunk_t *plain)
+{
+	DBG1(DBG_LIB, "encryption scheme %N not supported", encryption_scheme_names,
+		 scheme);
+	return FALSE;
+}
+
+METHOD(public_key_t, get_keysize, int,
+	private_public_key_t *this)
+{
+	return openssl_ed_keysize(this->type);
+}
+
+/**
+ * Calculate fingerprint from an EdDSA key, also used in ed private key.
+ */
+bool openssl_ed_fingerprint(EVP_PKEY *key, cred_encoding_type_t type,
+							chunk_t *fp)
+{
+	hasher_t *hasher;
+	chunk_t blob;
+	u_char *p;
+
+	if (lib->encoding->get_cache(lib->encoding, type, key, fp))
+	{
+		return TRUE;
+	}
+	switch (type)
+	{
+		case KEYID_PUBKEY_SHA1:
+			if (!EVP_PKEY_get_raw_public_key(key, NULL, &blob.len))
+			{
+				return FALSE;
+			}
+			blob = chunk_alloca(blob.len);
+			if (!EVP_PKEY_get_raw_public_key(key, blob.ptr, &blob.len))
+			{
+				return FALSE;
+			}
+			break;
+		case KEYID_PUBKEY_INFO_SHA1:
+			blob = chunk_alloca(i2d_PUBKEY(key, NULL));
+			p = blob.ptr;
+			i2d_PUBKEY(key, &p);
+			break;
+		default:
+			return FALSE;
+	}
+	hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+	if (!hasher || !hasher->allocate_hash(hasher, blob, fp))
+	{
+		DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed");
+		DESTROY_IF(hasher);
+		return FALSE;
+	}
+	hasher->destroy(hasher);
+	lib->encoding->cache(lib->encoding, type, key, *fp);
+	return TRUE;
+}
+
+METHOD(public_key_t, get_fingerprint, bool,
+	private_public_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint)
+{
+	return openssl_ed_fingerprint(this->key, type, fingerprint);
+}
+
+METHOD(public_key_t, get_encoding, bool,
+	private_public_key_t *this, cred_encoding_type_t type, chunk_t *encoding)
+{
+	bool success = TRUE;
+	u_char *p;
+
+	*encoding = chunk_alloc(i2d_PUBKEY(this->key, NULL));
+	p = encoding->ptr;
+	i2d_PUBKEY(this->key, &p);
+
+	if (type != PUBKEY_SPKI_ASN1_DER)
+	{
+		chunk_t asn1_encoding = *encoding;
+
+		success = lib->encoding->encode(lib->encoding, type,
+								NULL, encoding, CRED_PART_EDDSA_PUB_ASN1_DER,
+								asn1_encoding, CRED_PART_END);
+		chunk_clear(&asn1_encoding);
+	}
+	return success;
+}
+
+METHOD(public_key_t, get_ref, public_key_t*,
+	private_public_key_t *this)
+{
+	ref_get(&this->ref);
+	return &this->public;
+}
+
+METHOD(public_key_t, destroy, void,
+	private_public_key_t *this)
+{
+	if (ref_put(&this->ref))
+	{
+		lib->encoding->clear_cache(lib->encoding, this->key);
+		EVP_PKEY_free(this->key);
+		free(this);
+	}
+}
+
+/**
+ * Generic private constructor
+ */
+static private_public_key_t *create_empty(key_type_t type)
+{
+	private_public_key_t *this;
+
+	INIT(this,
+		.public = {
+			.get_type = _get_type,
+			.verify = _verify,
+			.encrypt = _encrypt,
+			.get_keysize = _get_keysize,
+			.equals = public_key_equals,
+			.get_fingerprint = _get_fingerprint,
+			.has_fingerprint = public_key_has_fingerprint,
+			.get_encoding = _get_encoding,
+			.get_ref = _get_ref,
+			.destroy = _destroy,
+		},
+		.type = type,
+		.ref = 1,
+	);
+
+	return this;
+}
+
+/*
+ * Described in header
+ */
+public_key_t *openssl_ed_public_key_load(key_type_t type, va_list args)
+{
+	private_public_key_t *this;
+	chunk_t blob = chunk_empty, pub = chunk_empty;
+	EVP_PKEY *key = NULL;
+
+	while (TRUE)
+	{
+		switch (va_arg(args, builder_part_t))
+		{
+			case BUILD_BLOB_ASN1_DER:
+				blob = va_arg(args, chunk_t);
+				continue;
+			case BUILD_EDDSA_PUB:
+				pub = va_arg(args, chunk_t);
+				continue;
+			case BUILD_END:
+				break;
+			default:
+				return NULL;
+		}
+		break;
+	}
+
+	if (pub.len)
+	{
+		key = EVP_PKEY_new_raw_public_key(openssl_ed_key_type(type), NULL,
+										  pub.ptr, pub.len);
+	}
+	else if (blob.len)
+	{
+		key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
+		if (key && EVP_PKEY_base_id(key) != openssl_ed_key_type(type))
+		{
+			EVP_PKEY_free(key);
+			return NULL;
+		}
+	}
+	if (!key)
+	{
+		return NULL;
+	}
+	this = create_empty(type);
+	this->key = key;
+	return &this->public;
+}
+
+#endif /* OPENSSL_VERSION_NUMBER */
diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_public_key.h b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.h
new file mode 100644
index 000000000..c4e1ba3ed
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 openssl_ed_public_key openssl_ed_public_key
+ * @{ @ingroup openssl_p
+ */
+
+#ifndef OPENSSL_ED_PUBLIC_KEY_H_
+#define OPENSSL_ED_PUBLIC_KEY_H_
+
+#include <credentials/builder.h>
+#include <credentials/keys/public_key.h>
+
+/**
+ * Load an EdDSA public key using OpenSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type		type of the key, must be KEY_ED25519 or KEY_ED448
+ * @param args		builder_part_t argument list
+ * @return 			loaded key, NULL on failure
+ */
+public_key_t *openssl_ed_public_key_load(key_type_t type, va_list args);
+
+#endif /** OPENSSL_ED_PUBLIC_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c
index 8b0a7c5c7..cbeb6c3b7 100644
--- a/src/libstrongswan/plugins/openssl/openssl_plugin.c
+++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2016 Tobias Brunner
+ * Copyright (C) 2008-2018 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -47,6 +47,9 @@
 #include "openssl_rng.h"
 #include "openssl_hmac.h"
 #include "openssl_gcm.h"
+#include "openssl_x_diffie_hellman.h"
+#include "openssl_ed_public_key.h"
+#include "openssl_ed_private_key.h"
 
 #ifndef FIPS_MODE
 #define FIPS_MODE 0
@@ -307,6 +310,11 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args)
 				case EVP_PKEY_EC:
 					return openssl_ec_private_key_create(key, FALSE);
 #endif
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
+				case EVP_PKEY_ED25519:
+				case EVP_PKEY_ED448:
+					return openssl_ed_private_key_create(key, FALSE);
+#endif /* OPENSSL_VERSION_NUMBER */
 				default:
 					EVP_PKEY_free(key);
 					break;
@@ -370,7 +378,7 @@ static private_key_t *openssl_private_key_connect(key_type_t type,
 #ifndef OPENSSL_NO_ENGINE
 	char *engine_id = NULL;
 	char keyname[BUF_LEN];
-	chunk_t keyid = chunk_empty;;
+	chunk_t keyid = chunk_empty;
 	EVP_PKEY *key;
 	ENGINE *engine;
 	int slot = -1;
@@ -395,7 +403,7 @@ static private_key_t *openssl_private_key_connect(key_type_t type,
 		}
 		break;
 	}
-	if (!keyid.len || keyid.len > 40)
+	if (!keyid.len)
 	{
 		return NULL;
 	}
@@ -405,7 +413,7 @@ static private_key_t *openssl_private_key_connect(key_type_t type,
 	{
 		snprintf(keyname, sizeof(keyname), "%d:", slot);
 	}
-	if (sizeof(keyname) - strlen(keyname) <= keyid.len * 4 / 3 + 1)
+	if (sizeof(keyname) - strlen(keyname) <= keyid.len * 2 + 1)
 	{
 		return NULL;
 	}
@@ -428,21 +436,21 @@ static private_key_t *openssl_private_key_connect(key_type_t type,
 		ENGINE_free(engine);
 		return NULL;
 	}
+	ENGINE_free(engine);
 	if (!login(engine, keyid))
 	{
 		DBG1(DBG_LIB, "login to engine '%s' failed", engine_id);
-		ENGINE_free(engine);
+		ENGINE_finish(engine);
 		return NULL;
 	}
 	key = ENGINE_load_private_key(engine, keyname, NULL, NULL);
+	ENGINE_finish(engine);
 	if (!key)
 	{
 		DBG1(DBG_LIB, "failed to load private key with ID '%s' from "
 			 "engine '%s'", keyname, engine_id);
-		ENGINE_free(engine);
 		return NULL;
 	}
-	ENGINE_free(engine);
 
 	switch (EVP_PKEY_base_id(key))
 	{
@@ -454,6 +462,11 @@ static private_key_t *openssl_private_key_connect(key_type_t type,
 		case EVP_PKEY_EC:
 			return openssl_ec_private_key_create(key, TRUE);
 #endif
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
+		case EVP_PKEY_ED25519:
+		case EVP_PKEY_ED448:
+			return openssl_ed_private_key_create(key, TRUE);
+#endif /* OPENSSL_VERSION_NUMBER */
 		default:
 			EVP_PKEY_free(key);
 			break;
@@ -594,7 +607,7 @@ METHOD(plugin_t, get_features, int,
 			PLUGIN_PROVIDE(DH, ECP_384_BP),
 			PLUGIN_PROVIDE(DH, ECP_512_BP),
 			PLUGIN_PROVIDE(DH, ECP_224_BP),
-#endif
+#endif /* OPENSSL_NO_ECDH */
 #ifndef OPENSSL_NO_DH
 		/* MODP DH groups */
 		PLUGIN_REGISTER(DH, openssl_diffie_hellman_create),
@@ -699,6 +712,30 @@ METHOD(plugin_t, get_features, int,
 		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_521),
 #endif
 #endif /* OPENSSL_NO_ECDSA */
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
+		PLUGIN_REGISTER(DH, openssl_x_diffie_hellman_create),
+			/* available since 1.1.0a, but we require 1.1.1 features */
+			PLUGIN_PROVIDE(DH, CURVE_25519),
+			/* available since 1.1.1 */
+			PLUGIN_PROVIDE(DH, CURVE_448),
+		/* EdDSA private/public key loading */
+		PLUGIN_REGISTER(PUBKEY, openssl_ed_public_key_load, TRUE),
+			PLUGIN_PROVIDE(PUBKEY, KEY_ED25519),
+			PLUGIN_PROVIDE(PUBKEY, KEY_ED448),
+		PLUGIN_REGISTER(PRIVKEY, openssl_ed_private_key_load, TRUE),
+			PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519),
+			PLUGIN_PROVIDE(PRIVKEY, KEY_ED448),
+		PLUGIN_REGISTER(PRIVKEY_GEN, openssl_ed_private_key_gen, FALSE),
+			PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ED25519),
+			PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ED448),
+		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ED25519),
+		PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ED448),
+		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ED25519),
+		PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ED448),
+		/* register a pro forma identity hasher, never instantiated */
+		PLUGIN_REGISTER(HASHER, return_null),
+			PLUGIN_PROVIDE(HASHER, HASH_IDENTITY),
+#endif /* OPENSSL_VERSION_NUMBER && !OPENSSL_NO_EC */
 		/* generic key loader */
 		PLUGIN_REGISTER(PRIVKEY, openssl_private_key_load, TRUE),
 			PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
diff --git a/src/libstrongswan/plugins/openssl/openssl_rng.c b/src/libstrongswan/plugins/openssl/openssl_rng.c
index a25b6b4b6..d3993749f 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rng.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rng.c
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2012-2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2012 Aleksandr Grinberg
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,7 +27,6 @@
 #include <utils/debug.h>
 
 #include <openssl/rand.h>
-#include <openssl/err.h>
 
 #include "openssl_rng.h"
 
@@ -49,6 +51,13 @@ struct private_openssl_rng_t {
 METHOD(rng_t, get_bytes, bool,
 	private_openssl_rng_t *this, size_t bytes, uint8_t *buffer)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
+	if (this->quality > RNG_WEAK)
+	{	/* use a separate DRBG for data we want to keep private, compared
+		 * to e.g. nonces */
+		return RAND_priv_bytes((char*)buffer, bytes) == 1;
+	}
+#endif
 	return RAND_bytes((char*)buffer, bytes) == 1;
 }
 
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
index 401a51a0b..8a9fdfe25 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
@@ -103,13 +103,8 @@ static bool build_signature(private_openssl_rsa_private_key_t *this,
 	if (pss)
 	{
 		const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash);
-		int slen = EVP_MD_size(md);
-		if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
-		{
-			slen = pss->salt_len;
-		}
 		if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
-			EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 ||
+			EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, pss->salt_len) <= 0 ||
 			EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0)
 		{
 			goto error;
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
index 20bf30ae9..38b4eda35 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
@@ -95,13 +95,8 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this,
 	if (pss)
 	{
 		const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash);
-		int slen = EVP_MD_size(md);
-		if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
-		{
-			slen = pss->salt_len;
-		}
 		if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
-			EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 ||
+			EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, pss->salt_len) <= 0 ||
 			EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0)
 		{
 			goto error;
diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c
index b7f969f73..f99dcd6b1 100644
--- a/src/libstrongswan/plugins/openssl/openssl_util.c
+++ b/src/libstrongswan/plugins/openssl/openssl_util.c
@@ -26,6 +26,7 @@
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
 #define OBJ_get0_data(o) ((o)->data)
 #define OBJ_length(o) ((o)->length)
+#define ASN1_STRING_get0_data(a) ASN1_STRING_data((ASN1_STRING*)a)
 #endif
 
 /**
@@ -164,11 +165,12 @@ chunk_t openssl_asn1_obj2chunk(ASN1_OBJECT *asn1)
 /**
  * Described in header.
  */
-chunk_t openssl_asn1_str2chunk(ASN1_STRING *asn1)
+chunk_t openssl_asn1_str2chunk(const ASN1_STRING *asn1)
 {
 	if (asn1)
 	{
-		return chunk_create(ASN1_STRING_data(asn1), ASN1_STRING_length(asn1));
+		return chunk_create((u_char*)ASN1_STRING_get0_data(asn1),
+							ASN1_STRING_length(asn1));
 	}
 	return chunk_empty;
 }
@@ -212,7 +214,7 @@ int openssl_asn1_known_oid(ASN1_OBJECT *obj)
 /**
  * Described in header.
  */
-time_t openssl_asn1_to_time(ASN1_TIME *time)
+time_t openssl_asn1_to_time(const ASN1_TIME *time)
 {
 	chunk_t chunk;
 
diff --git a/src/libstrongswan/plugins/openssl/openssl_util.h b/src/libstrongswan/plugins/openssl/openssl_util.h
index 80e557fa8..4afe76bf2 100644
--- a/src/libstrongswan/plugins/openssl/openssl_util.h
+++ b/src/libstrongswan/plugins/openssl/openssl_util.h
@@ -109,7 +109,7 @@ chunk_t openssl_asn1_obj2chunk(ASN1_OBJECT *asn1);
  * @param asn1		asn1 string to convert
  * @return			chunk, pointing into asn1 string
  */
-chunk_t openssl_asn1_str2chunk(ASN1_STRING *asn1);
+chunk_t openssl_asn1_str2chunk(const ASN1_STRING *asn1);
 
 /**
  * Convert an openssl X509_NAME to a identification_t of type ID_DER_ASN1_DN.
@@ -133,7 +133,7 @@ int openssl_asn1_known_oid(ASN1_OBJECT *obj);
  * @param time		openssl ASN1_TIME
  * @returns			time_t, 0 on error
  */
-time_t openssl_asn1_to_time(ASN1_TIME *time);
+time_t openssl_asn1_to_time(const ASN1_TIME *time);
 
 /**
  * Compatibility macros
diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c
index fae2d678f..fe21b0221 100644
--- a/src/libstrongswan/plugins/openssl/openssl_x509.c
+++ b/src/libstrongswan/plugins/openssl/openssl_x509.c
@@ -389,7 +389,11 @@ METHOD(certificate_t, issued_by, bool,
 	public_key_t *key;
 	bool valid;
 	x509_t *x509 = (x509_t*)issuer;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	const ASN1_BIT_STRING *sig;
+#else
 	ASN1_BIT_STRING *sig;
+#endif
 	chunk_t tbs;
 
 	if (&this->public.x509.interface == issuer)
@@ -993,7 +997,7 @@ static bool parse_subjectKeyIdentifier_ext(private_openssl_x509_t *this,
  */
 static bool parse_extensions(private_openssl_x509_t *this)
 {
-	STACK_OF(X509_EXTENSION) *extensions;
+	const STACK_OF(X509_EXTENSION) *extensions;
 	int i, num;
 
 	/* unless we see a keyUsage extension we are compliant with RFC 4945 */
@@ -1077,7 +1081,11 @@ static bool parse_certificate(private_openssl_x509_t *this)
 	hasher_t *hasher;
 	chunk_t chunk, sig_scheme, sig_scheme_tbs;
 	ASN1_OBJECT *oid;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	const X509_ALGOR *alg;
+#else
 	X509_ALGOR *alg;
+#endif
 
 	this->x509 = d2i_X509(NULL, &ptr, this->encoding.len);
 	if (!this->x509)
@@ -1135,9 +1143,9 @@ static bool parse_certificate(private_openssl_x509_t *this)
 	/* while X509_ALGOR_cmp() is declared in the headers of older OpenSSL
 	 * versions, at least on Ubuntu 14.04 it is not actually defined */
 	X509_get0_signature(NULL, &alg, this->x509);
-	sig_scheme = openssl_i2chunk(X509_ALGOR, alg);
+	sig_scheme = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg);
 	alg = X509_get0_tbs_sigalg(this->x509);
-	sig_scheme_tbs = openssl_i2chunk(X509_ALGOR, alg);
+	sig_scheme_tbs = openssl_i2chunk(X509_ALGOR, (X509_ALGOR*)alg);
 	if (!chunk_equals(sig_scheme, sig_scheme_tbs))
 	{
 		free(sig_scheme_tbs.ptr);
diff --git a/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c
new file mode 100644
index 000000000..37943f5bf
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 <openssl/evp.h>
+
+/* basic support for X25519 was added with 1.1.0a, but we require features (e.g.
+ * to load the keys) that were only added with 1.1.1 */
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_ECDH)
+
+#include "openssl_x_diffie_hellman.h"
+
+#include <utils/debug.h>
+
+typedef struct private_diffie_hellman_t private_diffie_hellman_t;
+
+/**
+ * Private data
+ */
+struct private_diffie_hellman_t {
+	/**
+	 * Public interface.
+	 */
+	diffie_hellman_t public;
+
+	/**
+	 * Diffie Hellman group number.
+	 */
+	diffie_hellman_group_t group;
+
+	/**
+	 * Private (public) key
+	 */
+	EVP_PKEY *key;
+
+	/**
+	 * Shared secret
+	 */
+	chunk_t shared_secret;
+
+	/**
+	 * True if shared secret is computed
+	 */
+	bool computed;
+};
+
+/**
+ * Map a DH group to a key type
+ */
+static int map_key_type(diffie_hellman_group_t group)
+{
+	switch (group)
+	{
+		case CURVE_25519:
+			return EVP_PKEY_X25519;
+		case CURVE_448:
+			return EVP_PKEY_X448;
+		default:
+			return 0;
+	}
+}
+
+/**
+ * Compute the shared secret
+ */
+static bool compute_shared_key(private_diffie_hellman_t *this, EVP_PKEY *pub,
+							   chunk_t *shared_secret)
+{
+	EVP_PKEY_CTX *ctx;
+	bool success = FALSE;
+
+	ctx = EVP_PKEY_CTX_new(this->key, NULL);
+	if (!ctx)
+	{
+		return FALSE;
+	}
+
+	if (EVP_PKEY_derive_init(ctx) <= 0)
+	{
+		goto error;
+	}
+
+	if (EVP_PKEY_derive_set_peer(ctx, pub) <= 0)
+	{
+		goto error;
+	}
+
+	if (EVP_PKEY_derive(ctx, NULL, &shared_secret->len) <= 0)
+	{
+		goto error;
+	}
+
+	*shared_secret = chunk_alloc(shared_secret->len);
+
+	if (EVP_PKEY_derive(ctx, shared_secret->ptr, &shared_secret->len) <= 0)
+	{
+		goto error;
+	}
+
+	success = TRUE;
+
+error:
+	EVP_PKEY_CTX_free(ctx);
+	return success;
+}
+
+METHOD(diffie_hellman_t, set_other_public_value, bool,
+	private_diffie_hellman_t *this, chunk_t value)
+{
+	EVP_PKEY *pub;
+
+	if (!diffie_hellman_verify_value(this->group, value))
+	{
+		return FALSE;
+	}
+
+	pub =  EVP_PKEY_new_raw_public_key(map_key_type(this->group), NULL,
+                                       value.ptr, value.len);
+	if (!pub)
+	{
+		DBG1(DBG_LIB, "%N public value is malformed",
+			 diffie_hellman_group_names, this->group);
+		return FALSE;
+	}
+
+	chunk_clear(&this->shared_secret);
+
+	if (!compute_shared_key(this, pub, &this->shared_secret))
+	{
+		DBG1(DBG_LIB, "%N shared secret computation failed",
+			 diffie_hellman_group_names, this->group);
+		EVP_PKEY_free(pub);
+		return FALSE;
+	}
+	this->computed = TRUE;
+	EVP_PKEY_free(pub);
+	return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_my_public_value, bool,
+	private_diffie_hellman_t *this, chunk_t *value)
+{
+	size_t len;
+
+	if (!EVP_PKEY_get_raw_public_key(this->key, NULL, &len))
+	{
+		return FALSE;
+	}
+
+	*value = chunk_alloc(len);
+
+	if (!EVP_PKEY_get_raw_public_key(this->key, value->ptr, &value->len))
+	{
+		chunk_free(value);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+METHOD(diffie_hellman_t, set_private_value, bool,
+	private_diffie_hellman_t *this, chunk_t value)
+{
+	EVP_PKEY_free(this->key);
+	this->key = EVP_PKEY_new_raw_private_key(map_key_type(this->group), NULL,
+											 value.ptr, value.len);
+	if (!this->key)
+	{
+		return FALSE;
+	}
+	return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_shared_secret, bool,
+	private_diffie_hellman_t *this, chunk_t *secret)
+{
+	if (!this->computed)
+	{
+		return FALSE;
+	}
+	*secret = chunk_clone(this->shared_secret);
+	return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
+	private_diffie_hellman_t *this)
+{
+	return this->group;
+}
+
+METHOD(diffie_hellman_t, destroy, void,
+	private_diffie_hellman_t *this)
+{
+	EVP_PKEY_free(this->key);
+	chunk_clear(&this->shared_secret);
+	free(this);
+}
+
+/*
+ * Described in header
+ */
+diffie_hellman_t *openssl_x_diffie_hellman_create(diffie_hellman_group_t group)
+{
+	private_diffie_hellman_t *this;
+	EVP_PKEY_CTX *ctx = NULL;
+	EVP_PKEY *key = NULL;
+
+	switch (group)
+	{
+		case CURVE_25519:
+			ctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL);
+			break;
+		case CURVE_448:
+			ctx = EVP_PKEY_CTX_new_id(NID_X448, NULL);
+			break;
+		default:
+			break;
+	}
+
+	if (!ctx ||
+		EVP_PKEY_keygen_init(ctx) <= 0 ||
+		EVP_PKEY_keygen(ctx, &key) <= 0)
+	{
+		DBG1(DBG_LIB, "generating key for %N failed",
+			 diffie_hellman_group_names, group);
+		EVP_PKEY_CTX_free(ctx);
+		return NULL;
+	}
+	EVP_PKEY_CTX_free(ctx);
+
+	INIT(this,
+		.public = {
+			.get_shared_secret = _get_shared_secret,
+			.set_other_public_value = _set_other_public_value,
+			.get_my_public_value = _get_my_public_value,
+			.set_private_value = _set_private_value,
+			.get_dh_group = _get_dh_group,
+			.destroy = _destroy,
+		},
+		.group = group,
+		.key = key,
+	);
+	return &this->public;
+}
+
+#endif /* OPENSSL_NO_ECDH */
diff --git a/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h
new file mode 100644
index 000000000..e28f38d15
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+/**
+ * Implementation of the X25519/X448 Diffie-Hellman algorithm using OpenSSL.
+ *
+ * @defgroup openssl_x_diffie_hellman openssl_x_diffie_hellman
+ * @{ @ingroup openssl_p
+ */
+
+#ifndef OPENSSL_X_DIFFIE_HELLMAN_H_
+#define OPENSSL_X_DIFFIE_HELLMAN_H_
+
+#include <library.h>
+
+/**
+ * Creates a new diffie_hellman_t object.
+ *
+ * @param group			Diffie Hellman group number to use
+ * @return				object, NULL if not supported
+ */
+diffie_hellman_t *openssl_x_diffie_hellman_create(diffie_hellman_group_t group);
+
+#endif /** OPENSSL_X_DIFFIE_HELLMAN_H_ @}*/
+
diff --git a/src/libstrongswan/plugins/sshkey/sshkey_builder.c b/src/libstrongswan/plugins/sshkey/sshkey_builder.c
index eab6559b3..934514249 100644
--- a/src/libstrongswan/plugins/sshkey/sshkey_builder.c
+++ b/src/libstrongswan/plugins/sshkey/sshkey_builder.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Tobias Brunner
+ * Copyright (C) 2013-2018 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -89,6 +89,34 @@ static sshkey_public_key_t *parse_public_key(chunk_t blob)
 		return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
 						BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
 	}
+	else if (chunk_equals(format, chunk_from_str("ssh-ed25519")))
+	{
+		chunk_t blob;
+
+		if (!reader->read_data32(reader, &blob))
+		{
+			DBG1(DBG_LIB, "invalid Ed25519 key in SSH key");
+			reader->destroy(reader);
+			return NULL;
+		}
+		reader->destroy(reader);
+		return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519,
+								  BUILD_EDDSA_PUB, blob, BUILD_END);
+	}
+	else if (chunk_equals(format, chunk_from_str("ssh-ed448")))
+	{
+		chunk_t blob;
+
+		if (!reader->read_data32(reader, &blob))
+		{
+			DBG1(DBG_LIB, "invalid Ed448 key in SSH key");
+			reader->destroy(reader);
+			return NULL;
+		}
+		reader->destroy(reader);
+		return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+								  BUILD_EDDSA_PUB, blob, BUILD_END);
+	}
 	else if (format.len > strlen(ECDSA_PREFIX) &&
 			 strpfx(format.ptr, ECDSA_PREFIX))
 	{
@@ -140,8 +168,9 @@ static sshkey_public_key_t *load_from_stream(FILE *file)
 	char line[1024], *token;
 
 	while (!public && fgets(line, sizeof(line), file))
-	{	/* the format is: ssh-rsa|ecdsa-... <key(base64)> <identifier> */
-		if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX))
+	{	/* the format is: ssh-<key-type> <key(base64)> <identifier> */
+		if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX) &&
+			!strpfx(line, "ssh-ed25519") && !strpfx(line, "ssh-ed448"))
 		{
 			continue;
 		}
diff --git a/src/libstrongswan/plugins/sshkey/sshkey_encoder.c b/src/libstrongswan/plugins/sshkey/sshkey_encoder.c
index 9f5f8bd1f..ed35fc010 100644
--- a/src/libstrongswan/plugins/sshkey/sshkey_encoder.c
+++ b/src/libstrongswan/plugins/sshkey/sshkey_encoder.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2013-2018 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -72,6 +72,42 @@ static bool build_public_key(chunk_t *encoding, va_list args)
 		writer->destroy(writer);
 		return TRUE;
 	}
+	else if (cred_encoding_args(args, CRED_PART_EDDSA_PUB_ASN1_DER, &n,
+								CRED_PART_END))
+	{
+		chunk_t alg;
+		char *prefix;
+		int oid;
+
+		/* parse subjectPublicKeyInfo */
+		if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE)
+		{
+			return FALSE;
+		}
+		oid = asn1_parse_algorithmIdentifier(n, 1, NULL);
+		switch (oid)
+		{
+			case OID_ED25519:
+				prefix = "ssh-ed25519";
+				break;
+			case OID_ED448:
+				prefix = "ssh-ed448";
+				break;
+			default:
+				return FALSE;
+		}
+		if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE ||
+			asn1_unwrap(&n, &n) != ASN1_BIT_STRING || !n.len)
+		{
+			return FALSE;
+		}
+		writer = bio_writer_create(0);
+		writer->write_data32(writer, chunk_from_str(prefix));
+		writer->write_data32(writer, chunk_skip(n, 1));
+		*encoding = chunk_to_base64(writer->get_buf(writer), NULL);
+		writer->destroy(writer);
+		return TRUE;
+	}
 	else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n,
 								CRED_PART_END))
 	{
diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.am b/src/libstrongswan/plugins/test_vectors/Makefile.am
index c4d9f2fc5..3d34cf7c9 100644
--- a/src/libstrongswan/plugins/test_vectors/Makefile.am
+++ b/src/libstrongswan/plugins/test_vectors/Makefile.am
@@ -49,6 +49,7 @@ libstrongswan_test_vectors_la_SOURCES = \
 	test_vectors/ecp.c \
 	test_vectors/ecpbp.c \
 	test_vectors/curve25519.c \
+	test_vectors/curve448.c \
 	test_vectors/rng.c
 
 libstrongswan_test_vectors_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.in b/src/libstrongswan/plugins/test_vectors/Makefile.in
index 7f6c319c6..ed3ae0f40 100644
--- a/src/libstrongswan/plugins/test_vectors/Makefile.in
+++ b/src/libstrongswan/plugins/test_vectors/Makefile.in
@@ -156,7 +156,8 @@ am_libstrongswan_test_vectors_la_OBJECTS = test_vectors_plugin.lo \
 	test_vectors/sha3_shake.lo test_vectors/fips_prf.lo \
 	test_vectors/modp.lo test_vectors/modpsub.lo \
 	test_vectors/ecp.lo test_vectors/ecpbp.lo \
-	test_vectors/curve25519.lo test_vectors/rng.lo
+	test_vectors/curve25519.lo test_vectors/curve448.lo \
+	test_vectors/rng.lo
 libstrongswan_test_vectors_la_OBJECTS =  \
 	$(am_libstrongswan_test_vectors_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -518,6 +519,7 @@ libstrongswan_test_vectors_la_SOURCES = \
 	test_vectors/ecp.c \
 	test_vectors/ecpbp.c \
 	test_vectors/curve25519.c \
+	test_vectors/curve448.c \
 	test_vectors/rng.c
 
 libstrongswan_test_vectors_la_LDFLAGS = -module -avoid-version
@@ -680,6 +682,8 @@ test_vectors/ecpbp.lo: test_vectors/$(am__dirstamp) \
 	test_vectors/$(DEPDIR)/$(am__dirstamp)
 test_vectors/curve25519.lo: test_vectors/$(am__dirstamp) \
 	test_vectors/$(DEPDIR)/$(am__dirstamp)
+test_vectors/curve448.lo: test_vectors/$(am__dirstamp) \
+	test_vectors/$(DEPDIR)/$(am__dirstamp)
 test_vectors/rng.lo: test_vectors/$(am__dirstamp) \
 	test_vectors/$(DEPDIR)/$(am__dirstamp)
 
@@ -710,6 +714,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@test_vectors/$(DEPDIR)/chacha20_xof.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@test_vectors/$(DEPDIR)/chacha20poly1305.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@test_vectors/$(DEPDIR)/curve25519.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@test_vectors/$(DEPDIR)/curve448.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@test_vectors/$(DEPDIR)/des.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@test_vectors/$(DEPDIR)/ecp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@test_vectors/$(DEPDIR)/ecpbp.Plo@am__quote@
diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors.h b/src/libstrongswan/plugins/test_vectors/test_vectors.h
index 7ab965a82..7c8ac0c6e 100644
--- a/src/libstrongswan/plugins/test_vectors/test_vectors.h
+++ b/src/libstrongswan/plugins/test_vectors/test_vectors.h
@@ -116,6 +116,7 @@ TEST_VECTOR_AEAD(aes_gcm23)
 TEST_VECTOR_AEAD(chacha20poly1305_1)
 TEST_VECTOR_AEAD(chacha20poly1305_2)
 TEST_VECTOR_AEAD(chacha20poly1305_3)
+TEST_VECTOR_AEAD(chacha20poly1305_4)
 
 TEST_VECTOR_SIGNER(aes_xcbc_s1)
 TEST_VECTOR_SIGNER(aes_xcbc_s2)
@@ -305,3 +306,4 @@ TEST_VECTOR_DH(ecp384bp)
 TEST_VECTOR_DH(ecp512bp)
 TEST_VECTOR_DH(curve25519_1)
 TEST_VECTOR_DH(curve25519_2)
+TEST_VECTOR_DH(curve448_1)
diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c b/src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c
index 21726cbbb..dcbfe5ca3 100644
--- a/src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c
+++ b/src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c
@@ -16,9 +16,39 @@
 #include <crypto/crypto_tester.h>
 
 /**
- * From draft-irtf-cfrg-chacha20-poly1305
+ * From RFC 7539
  */
 aead_test_vector_t chacha20poly1305_1 = {
+	.alg = ENCR_CHACHA20_POLY1305, .key_size = 32, .salt_size = 4,
+	.len = 114, .alen = 12,
+	.key	= "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\x07\x00\x00\x00",
+	.iv		= "\x40\x41\x42\x43\x44\x45\x46\x47",
+	.adata	= "\x50\x51\x52\x53\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
+	.plain	= "\x4c\x61\x64\x69\x65\x73\x20\x61\x6e\x64\x20\x47\x65\x6e\x74\x6c"
+			  "\x65\x6d\x65\x6e\x20\x6f\x66\x20\x74\x68\x65\x20\x63\x6c\x61\x73"
+			  "\x73\x20\x6f\x66\x20\x27\x39\x39\x3a\x20\x49\x66\x20\x49\x20\x63"
+			  "\x6f\x75\x6c\x64\x20\x6f\x66\x66\x65\x72\x20\x79\x6f\x75\x20\x6f"
+			  "\x6e\x6c\x79\x20\x6f\x6e\x65\x20\x74\x69\x70\x20\x66\x6f\x72\x20"
+			  "\x74\x68\x65\x20\x66\x75\x74\x75\x72\x65\x2c\x20\x73\x75\x6e\x73"
+			  "\x63\x72\x65\x65\x6e\x20\x77\x6f\x75\x6c\x64\x20\x62\x65\x20\x69"
+			  "\x74\x2e",
+	.cipher	= "\xd3\x1a\x8d\x34\x64\x8e\x60\xdb\x7b\x86\xaf\xbc\x53\xef\x7e\xc2"
+			  "\xa4\xad\xed\x51\x29\x6e\x08\xfe\xa9\xe2\xb5\xa7\x36\xee\x62\xd6"
+			  "\x3d\xbe\xa4\x5e\x8c\xa9\x67\x12\x82\xfa\xfb\x69\xda\x92\x72\x8b"
+			  "\x1a\x71\xde\x0a\x9e\x06\x0b\x29\x05\xd6\xa5\xb6\x7e\xcd\x3b\x36"
+			  "\x92\xdd\xbd\x7f\x2d\x77\x8b\x8c\x98\x03\xae\xe3\x28\x09\x1b\x58"
+			  "\xfa\xb3\x24\xe4\xfa\xd6\x75\x94\x55\x85\x80\x8b\x48\x31\xd7\xbc"
+			  "\x3f\xf4\xde\xf0\x8e\x4b\x7a\x9d\xe5\x76\xd2\x65\x86\xce\xc6\x4b"
+			  "\x61\x16\x1a\xe1\x0b\x59\x4f\x09\xe2\x6a\x7e\x90\x2e\xcb\xd0\x60"
+			  "\x06\x91",
+};
+
+/**
+ * Additional test vector from RFC 7539
+ */
+aead_test_vector_t chacha20poly1305_2 = {
 	.alg = ENCR_CHACHA20_POLY1305, .key_size = 32, .salt_size = 4,
 	.len = 265, .alen = 12,
 	.key	= "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
@@ -64,9 +94,9 @@ aead_test_vector_t chacha20poly1305_1 = {
 };
 
 /**
- * ESP example from draft-ietf-ipsecme-chacha20-poly1305-06
+ * ESP example from RFC 7634
  */
-aead_test_vector_t chacha20poly1305_2 = {
+aead_test_vector_t chacha20poly1305_3 = {
 	.alg = ENCR_CHACHA20_POLY1305, .key_size = 32, .salt_size = 4,
 	.len = 88, .alen = 8,
 	.key	= "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
@@ -90,9 +120,9 @@ aead_test_vector_t chacha20poly1305_2 = {
 };
 
 /**
- * IKEv2 example from draft-ietf-ipsecme-chacha20-poly1305-06
+ * IKEv2 example from RFC 7634
  */
-aead_test_vector_t chacha20poly1305_3 = {
+aead_test_vector_t chacha20poly1305_4 = {
 	.alg = ENCR_CHACHA20_POLY1305, .key_size = 32, .salt_size = 4,
 	.len = 13, .alen = 32,
 	.key	= "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c b/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c
index 676fcfc5a..23c024a37 100644
--- a/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c
+++ b/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c
@@ -16,7 +16,7 @@
 #include <crypto/crypto_tester.h>
 
 /**
- * From RFC 8037
+ * From RFC 7748
  */
 dh_test_vector_t curve25519_1 = {
 	.group = CURVE_25519, .priv_len = 32, .pub_len = 32, .shared_len = 32,
diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c b/src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c
new file mode 100644
index 000000000..fccbb808a
--- /dev/null
+++ b/src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 Licenseor (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 usefulbut
+ * 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 <crypto/crypto_tester.h>
+
+/**
+ * From RFC 7748
+ */
+dh_test_vector_t curve448_1 = {
+	.group = CURVE_448, .priv_len = 56, .pub_len = 56, .shared_len = 56,
+	.priv_a	= "\x9a\x8f\x49\x25\xd1\x51\x9f\x57\x75\xcf\x46\xb0\x4b\x58\x00\xd4"
+			  "\xee\x9e\xe8\xba\xe8\xbc\x55\x65\xd4\x98\xc2\x8d\xd9\xc9\xba\xf5"
+			  "\x74\xa9\x41\x97\x44\x89\x73\x91\x00\x63\x82\xa6\xf1\x27\xab\x1d"
+			  "\x9a\xc2\xd8\xc0\xa5\x98\x72\x6b",
+	.priv_b = "\x1c\x30\x6a\x7a\xc2\xa0\xe2\xe0\x99\x0b\x29\x44\x70\xcb\xa3\x39"
+			  "\xe6\x45\x37\x72\xb0\x75\x81\x1d\x8f\xad\x0d\x1d\x69\x27\xc1\x20"
+			  "\xbb\x5e\xe8\x97\x2b\x0d\x3e\x21\x37\x4c\x9c\x92\x1b\x09\xd1\xb0"
+			  "\x36\x6f\x10\xb6\x51\x73\x99\x2d",
+	.pub_a	= "\x9b\x08\xf7\xcc\x31\xb7\xe3\xe6\x7d\x22\xd5\xae\xa1\x21\x07\x4a"
+			  "\x27\x3b\xd2\xb8\x3d\xe0\x9c\x63\xfa\xa7\x3d\x2c\x22\xc5\xd9\xbb"
+			  "\xc8\x36\x64\x72\x41\xd9\x53\xd4\x0c\x5b\x12\xda\x88\x12\x0d\x53"
+			  "\x17\x7f\x80\xe5\x32\xc4\x1f\xa0",
+	.pub_b	= "\x3e\xb7\xa8\x29\xb0\xcd\x20\xf5\xbc\xfc\x0b\x59\x9b\x6f\xec\xcf"
+			  "\x6d\xa4\x62\x71\x07\xbd\xb0\xd4\xf3\x45\xb4\x30\x27\xd8\xb9\x72"
+			  "\xfc\x3e\x34\xfb\x42\x32\xa1\x3c\xa7\x06\xdc\xb5\x7a\xec\x3d\xae"
+			  "\x07\xbd\xc1\xc6\x7b\xf3\x36\x09",
+	.shared	= "\x07\xff\xf4\x18\x1a\xc6\xcc\x95\xec\x1c\x16\xa9\x4a\x0f\x74\xd1"
+			  "\x2d\xa2\x32\xce\x40\xa7\x75\x52\x28\x1d\x28\x2b\xb6\x0c\x0b\x56"
+			  "\xfd\x24\x64\xc3\x35\x54\x39\x36\x52\x1c\x24\x40\x30\x85\xd5\x9a"
+			  "\x44\x9a\x50\x37\x51\x4a\x87\x9d",
+};
diff --git a/src/libstrongswan/settings/settings_lexer.c b/src/libstrongswan/settings/settings_lexer.c
index c29dfa57b..a88a58f0e 100644
--- a/src/libstrongswan/settings/settings_lexer.c
+++ b/src/libstrongswan/settings/settings_lexer.c
@@ -7,7 +7,6 @@
 /* A lexical scanner generated by flex */
 
 /* %not-for-header */
-
 /* %if-c-only */
 /* %if-not-reentrant */
 /* %endif */
@@ -17,7 +16,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 0
+#define YY_FLEX_SUBMINOR_VERSION 4
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -26,9 +25,230 @@
 /* %endif */
 
 /* %if-c-only */
-    
+#ifdef yy_create_buffer
+#define settings_parser__create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer settings_parser__create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define settings_parser__delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer settings_parser__delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define settings_parser__scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer settings_parser__scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define settings_parser__scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string settings_parser__scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define settings_parser__scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes settings_parser__scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define settings_parser__init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer settings_parser__init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define settings_parser__flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer settings_parser__flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define settings_parser__load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state settings_parser__load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define settings_parser__switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer settings_parser__switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define settings_parser_push_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state settings_parser_push_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define settings_parser_pop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state settings_parser_pop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define settings_parser_ensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack settings_parser_ensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define settings_parser_lex_ALREADY_DEFINED
+#else
+#define yylex settings_parser_lex
+#endif
+
+#ifdef yyrestart
+#define settings_parser_restart_ALREADY_DEFINED
+#else
+#define yyrestart settings_parser_restart
+#endif
+
+#ifdef yylex_init
+#define settings_parser_lex_init_ALREADY_DEFINED
+#else
+#define yylex_init settings_parser_lex_init
+#endif
+
+#ifdef yylex_init_extra
+#define settings_parser_lex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra settings_parser_lex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define settings_parser_lex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy settings_parser_lex_destroy
+#endif
+
+#ifdef yyget_debug
+#define settings_parser_get_debug_ALREADY_DEFINED
+#else
+#define yyget_debug settings_parser_get_debug
+#endif
+
+#ifdef yyset_debug
+#define settings_parser_set_debug_ALREADY_DEFINED
+#else
+#define yyset_debug settings_parser_set_debug
+#endif
+
+#ifdef yyget_extra
+#define settings_parser_get_extra_ALREADY_DEFINED
+#else
+#define yyget_extra settings_parser_get_extra
+#endif
+
+#ifdef yyset_extra
+#define settings_parser_set_extra_ALREADY_DEFINED
+#else
+#define yyset_extra settings_parser_set_extra
+#endif
+
+#ifdef yyget_in
+#define settings_parser_get_in_ALREADY_DEFINED
+#else
+#define yyget_in settings_parser_get_in
+#endif
+
+#ifdef yyset_in
+#define settings_parser_set_in_ALREADY_DEFINED
+#else
+#define yyset_in settings_parser_set_in
+#endif
+
+#ifdef yyget_out
+#define settings_parser_get_out_ALREADY_DEFINED
+#else
+#define yyget_out settings_parser_get_out
+#endif
+
+#ifdef yyset_out
+#define settings_parser_set_out_ALREADY_DEFINED
+#else
+#define yyset_out settings_parser_set_out
+#endif
+
+#ifdef yyget_leng
+#define settings_parser_get_leng_ALREADY_DEFINED
+#else
+#define yyget_leng settings_parser_get_leng
+#endif
+
+#ifdef yyget_text
+#define settings_parser_get_text_ALREADY_DEFINED
+#else
+#define yyget_text settings_parser_get_text
+#endif
+
+#ifdef yyget_lineno
+#define settings_parser_get_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno settings_parser_get_lineno
+#endif
+
+#ifdef yyset_lineno
+#define settings_parser_set_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno settings_parser_set_lineno
+#endif
+
+#ifdef yyget_column
+#define settings_parser_get_column_ALREADY_DEFINED
+#else
+#define yyget_column settings_parser_get_column
+#endif
+
+#ifdef yyset_column
+#define settings_parser_set_column_ALREADY_DEFINED
+#else
+#define yyset_column settings_parser_set_column
+#endif
+
+#ifdef yywrap
+#define settings_parser_wrap_ALREADY_DEFINED
+#else
+#define yywrap settings_parser_wrap
+#endif
+
 /* %endif */
 
+#ifdef yyget_lval
+#define settings_parser_get_lval_ALREADY_DEFINED
+#else
+#define yyget_lval settings_parser_get_lval
+#endif
+
+#ifdef yyset_lval
+#define settings_parser_set_lval_ALREADY_DEFINED
+#else
+#define yyset_lval settings_parser_set_lval
+#endif
+
+#ifdef yyalloc
+#define settings_parser_alloc_ALREADY_DEFINED
+#else
+#define yyalloc settings_parser_alloc
+#endif
+
+#ifdef yyrealloc
+#define settings_parser_realloc_ALREADY_DEFINED
+#else
+#define yyrealloc settings_parser_realloc
+#endif
+
+#ifdef yyfree
+#define settings_parser_free_ALREADY_DEFINED
+#else
+#define yyfree settings_parser_free
+#endif
+
 /* %if-c-only */
 
 /* %endif */
@@ -108,50 +328,39 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#ifndef SIZE_MAX
+#define SIZE_MAX               (~(size_t)0)
+#endif
+
 #endif /* ! C99 */
 
 #endif /* ! FLEXINT_H */
 
 /* %endif */
 
+/* begin standard C++ headers. */
 /* %if-c++-only */
 /* %endif */
 
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else	/* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif	/* defined (__STDC__) */
-#endif	/* ! __cplusplus */
-
-#ifdef YY_USE_CONST
+/* TODO: this is always defined, so inline it */
 #define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
 #else
-#define yyconst
+#define yynoreturn
 #endif
 
 /* %not-for-header */
-
 /* Returned upon end-of-file. */
 #define YY_NULL 0
 /* %ok-for-header */
 
 /* %not-for-header */
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
+/* Promotes a possibly negative, possibly signed char to an
+ *   integer in range [0..255] for use as an array index.
  */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
 /* %ok-for-header */
 
 /* %if-reentrant */
@@ -183,20 +392,16 @@ typedef void* yyscan_t;
  * definition of BEGIN.
  */
 #define BEGIN yyg->yy_start = 1 + 2 *
-
 /* Translate the current start state into a value that can be later handed
  * to BEGIN to return to the state.  The YYSTATE alias is for lex
  * compatibility.
  */
 #define YY_START ((yyg->yy_start - 1) / 2)
 #define YYSTATE YY_START
-
 /* Action number for EOF rule of a given start state. */
 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
 /* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE settings_parser_restart(yyin ,yyscanner )
-
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
 #define YY_END_OF_BUFFER_CHAR 0
 
 /* Size of default input buffer. */
@@ -237,10 +442,10 @@ typedef size_t yy_size_t;
 #define EOB_ACT_CONTINUE_SCAN 0
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
-
+    
     /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
      *       access to the local variable yy_act. Since yyless() is a macro, it would break
-     *       existing scanners that call yyless() from OUTSIDE settings_parser_lex. 
+     *       existing scanners that call yyless() from OUTSIDE yylex.
      *       One obvious solution it to make yy_act a global. I tried that, and saw
      *       a 5% performance hit in a non-yylineno scanner, because yy_act is
      *       normally declared as a register variable-- so it is not worth it.
@@ -273,7 +478,6 @@ typedef size_t yy_size_t;
 		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
 		} \
 	while ( 0 )
-
 #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
 
 #ifndef YY_STRUCT_YY_BUFFER_STATE
@@ -293,7 +497,7 @@ struct yy_buffer_state
 	/* Size of input buffer in bytes, not including room for EOB
 	 * characters.
 	 */
-	yy_size_t yy_buf_size;
+	int yy_buf_size;
 
 	/* Number of characters read into yy_ch_buf, not including EOB
 	 * characters.
@@ -321,7 +525,7 @@ struct yy_buffer_state
 
     int yy_bs_lineno; /**< The line count. */
     int yy_bs_column; /**< The column count. */
-    
+
 	/* Whether to try to fill the input buffer when we reach the
 	 * end of it.
 	 */
@@ -338,7 +542,7 @@ struct yy_buffer_state
 	 * possible backing-up.
 	 *
 	 * When we actually see the EOF, we change the status to "new"
-	 * (via settings_parser_restart()), so that the user can continue scanning by
+	 * (via yyrestart()), so that the user can continue scanning by
 	 * just pointing yyin at a new input file.
 	 */
 #define YY_BUFFER_EOF_PENDING 2
@@ -348,7 +552,6 @@ struct yy_buffer_state
 
 /* %if-c-only Standard (non-C++) definition */
 /* %not-for-header */
-
 /* %if-not-reentrant */
 /* %endif */
 /* %ok-for-header */
@@ -364,7 +567,6 @@ struct yy_buffer_state
 #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
                           ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
                           : NULL)
-
 /* Same as previous macro, but useful when we know that the buffer stack is not
  * NULL or when we need an lvalue. For internal use only.
  */
@@ -374,57 +576,52 @@ struct yy_buffer_state
 
 /* %if-not-reentrant */
 /* %not-for-header */
-
 /* %ok-for-header */
 
 /* %endif */
 
-void settings_parser_restart (FILE *input_file ,yyscan_t yyscanner );
-void settings_parser__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE settings_parser__create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void settings_parser__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void settings_parser__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void settings_parser_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void settings_parser_pop_buffer_state (yyscan_t yyscanner );
-
-static void settings_parser_ensure_buffer_stack (yyscan_t yyscanner );
-static void settings_parser__load_buffer_state (yyscan_t yyscanner );
-static void settings_parser__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
 
-#define YY_FLUSH_BUFFER settings_parser__flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
 
-YY_BUFFER_STATE settings_parser__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE settings_parser__scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE settings_parser__scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
 
 /* %endif */
 
-void *settings_parser_alloc (yy_size_t ,yyscan_t yyscanner );
-void *settings_parser_realloc (void *,yy_size_t ,yyscan_t yyscanner );
-void settings_parser_free (void * ,yyscan_t yyscanner );
-
-#define yy_new_buffer settings_parser__create_buffer
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
 
+#define yy_new_buffer yy_create_buffer
 #define yy_set_interactive(is_interactive) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){ \
-        settings_parser_ensure_buffer_stack (yyscanner); \
+        yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            settings_parser__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
 	}
-
 #define yy_set_bol(at_bol) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){\
-        settings_parser_ensure_buffer_stack (yyscanner); \
+        yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            settings_parser__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
 	}
-
 #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
 
 /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
@@ -434,8 +631,7 @@ void settings_parser_free (void * ,yyscan_t yyscanner );
 #define YY_SKIP_YYWRAP
 
 #define FLEX_DEBUG
-
-typedef unsigned char YY_CHAR;
+typedef flex_uint8_t YY_CHAR;
 
 typedef int yy_state_type;
 
@@ -445,13 +641,10 @@ typedef int yy_state_type;
 
 /* %if-c-only Standard (non-C++) definition */
 
-static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
-static int yy_get_next_buffer (yyscan_t yyscanner );
-#if defined(__GNUC__) && __GNUC__ >= 3
-__attribute__((__noreturn__))
-#endif
-static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state  , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
 
 /* %endif */
 
@@ -461,12 +654,11 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
 #define YY_DO_BEFORE_ACTION \
 	yyg->yytext_ptr = yy_bp; \
 /* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
-	yyleng = (size_t) (yy_cp - yy_bp); \
+	yyleng = (int) (yy_cp - yy_bp); \
 	yyg->yy_hold_char = *yy_cp; \
 	*yy_cp = '\0'; \
 /* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
 	yyg->yy_c_buf_p = yy_cp;
-
 /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
 #define YY_NUM_RULES 39
 #define YY_END_OF_BUFFER 40
@@ -477,7 +669,7 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[85] =
+static const flex_int16_t yy_accept[85] =
     {   0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
        40,   12,    2,    3,    2,   11,    1,    7,    6,    8,
@@ -490,7 +682,7 @@ static yyconst flex_int16_t yy_accept[85] =
         0,   10,   10,    0
     } ;
 
-static yyconst YY_CHAR yy_ec[256] =
+static const YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
@@ -522,14 +714,14 @@ static yyconst YY_CHAR yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst YY_CHAR yy_meta[24] =
+static const YY_CHAR yy_meta[24] =
     {   0,
         1,    2,    3,    4,    5,    6,    5,    7,    8,    7,
         9,   10,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    7,    5
     } ;
 
-static yyconst flex_uint16_t yy_base[103] =
+static const flex_int16_t yy_base[103] =
     {   0,
         0,    0,   23,    0,   45,   67,   89,  111,   49,   50,
       124,    0,  133,  335,   55,  335,   60,  335,  335,  335,
@@ -545,7 +737,7 @@ static yyconst flex_uint16_t yy_base[103] =
       314,  324
     } ;
 
-static yyconst flex_int16_t yy_def[103] =
+static const flex_int16_t yy_def[103] =
     {   0,
        84,    1,   84,    3,   85,   85,   86,   86,   87,   87,
        84,   88,   84,   84,   84,   84,   89,   84,   84,   84,
@@ -561,7 +753,7 @@ static yyconst flex_int16_t yy_def[103] =
        84,   84
     } ;
 
-static yyconst flex_uint16_t yy_nxt[359] =
+static const flex_int16_t yy_nxt[359] =
     {   0,
        12,   13,   14,   15,   13,   16,   17,   18,   19,   20,
        21,   12,   12,   12,   12,   22,   12,   12,   12,   12,
@@ -604,7 +796,7 @@ static yyconst flex_uint16_t yy_nxt[359] =
        84,   84,   84,   84,   84,   84,   84,   84
     } ;
 
-static yyconst flex_int16_t yy_chk[359] =
+static const flex_int16_t yy_chk[359] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -648,18 +840,18 @@ static yyconst flex_int16_t yy_chk[359] =
     } ;
 
 /* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[40] =
+static const flex_int32_t yy_rule_can_match_eol[40] =
     {   0,
 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 
     0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 
         };
 
-static yyconst flex_int16_t yy_rule_linenum[39] =
+static const flex_int16_t yy_rule_linenum[39] =
     {   0,
-       66,   67,   68,   70,   71,   73,   74,   76,   81,   86,
-       91,   96,  102,  103,  104,  106,  108,  113,  120,  121,
-      123,  144,  150,  157,  160,  180,  183,  186,  189,  195,
-      196,  198,  218,  219,  220,  221,  222,  223
+       71,   72,   73,   75,   76,   78,   79,   81,   86,   91,
+       96,  101,  107,  108,  109,  111,  113,  118,  125,  126,
+      128,  149,  155,  162,  165,  185,  188,  191,  194,  200,
+      201,  203,  223,  224,  225,  226,  227,  228
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -694,9 +886,13 @@ bool settings_parser_open_next_file(parser_helper_t *ctx);
 
 static void include_files(parser_helper_t *ctx);
 
+#line 890 "settings/settings_lexer.c"
 /* use start conditions stack */
 /* do not declare unneeded functions */
 #define YY_NO_INPUT 1
+/* do not include unistd.h as it might conflict with our scanner states */
+#define YY_NO_UNISTD_H 1
+/* due to that disable interactive mode, which requires isatty() */
 /* don't use global variables, and interact properly with bison */
 /* maintain the line number */
 /* don't generate a default rule */
@@ -712,7 +908,7 @@ static void include_files(parser_helper_t *ctx);
 /* state used to scan quoted strings */
 
 /* pattern for section/key names */
-#line 716 "settings/settings_lexer.c"
+#line 912 "settings/settings_lexer.c"
 
 #define INITIAL 0
 #define ref 1
@@ -751,7 +947,7 @@ struct yyguts_t
     YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
     char yy_hold_char;
     int yy_n_chars;
-    yy_size_t yyleng_r;
+    int yyleng_r;
     char *yy_c_buf_p;
     int yy_init;
     int yy_start;
@@ -775,7 +971,7 @@ struct yyguts_t
 
 /* %if-c-only */
 
-static int yy_init_globals (yyscan_t yyscanner );
+static int yy_init_globals ( yyscan_t yyscanner );
 
 /* %endif */
 
@@ -785,9 +981,9 @@ static int yy_init_globals (yyscan_t yyscanner );
      * from bison output in section 1.*/
     #    define yylval yyg->yylval_r
     
-int settings_parser_lex_init (yyscan_t* scanner);
+int yylex_init (yyscan_t* scanner);
 
-int settings_parser_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
 
 /* %endif */
 
@@ -796,41 +992,41 @@ int settings_parser_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner
 /* Accessor methods to globals.
    These are made visible to non-reentrant scanners for convenience. */
 
-int settings_parser_lex_destroy (yyscan_t yyscanner );
+int yylex_destroy ( yyscan_t yyscanner );
 
-int settings_parser_get_debug (yyscan_t yyscanner );
+int yyget_debug ( yyscan_t yyscanner );
 
-void settings_parser_set_debug (int debug_flag ,yyscan_t yyscanner );
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
 
-YY_EXTRA_TYPE settings_parser_get_extra (yyscan_t yyscanner );
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
 
-void settings_parser_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
 
-FILE *settings_parser_get_in (yyscan_t yyscanner );
+FILE *yyget_in ( yyscan_t yyscanner );
 
-void settings_parser_set_in  (FILE * _in_str ,yyscan_t yyscanner );
+void yyset_in  ( FILE * _in_str , yyscan_t yyscanner );
 
-FILE *settings_parser_get_out (yyscan_t yyscanner );
+FILE *yyget_out ( yyscan_t yyscanner );
 
-void settings_parser_set_out  (FILE * _out_str ,yyscan_t yyscanner );
+void yyset_out  ( FILE * _out_str , yyscan_t yyscanner );
 
-yy_size_t settings_parser_get_leng (yyscan_t yyscanner );
+			int yyget_leng ( yyscan_t yyscanner );
 
-char *settings_parser_get_text (yyscan_t yyscanner );
+char *yyget_text ( yyscan_t yyscanner );
 
-int settings_parser_get_lineno (yyscan_t yyscanner );
+int yyget_lineno ( yyscan_t yyscanner );
 
-void settings_parser_set_lineno (int _line_number ,yyscan_t yyscanner );
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
 
-int settings_parser_get_column  (yyscan_t yyscanner );
+int yyget_column  ( yyscan_t yyscanner );
 
-void settings_parser_set_column (int _column_no ,yyscan_t yyscanner );
+void yyset_column ( int _column_no , yyscan_t yyscanner );
 
 /* %if-bison-bridge */
 
-YYSTYPE * settings_parser_get_lval (yyscan_t yyscanner );
+YYSTYPE * yyget_lval ( yyscan_t yyscanner );
 
-void settings_parser_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
 
 /* %endif */
 
@@ -840,17 +1036,16 @@ void settings_parser_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
 
 #ifndef YY_SKIP_YYWRAP
 #ifdef __cplusplus
-extern "C" int settings_parser_wrap (yyscan_t yyscanner );
+extern "C" int yywrap ( yyscan_t yyscanner );
 #else
-extern int settings_parser_wrap (yyscan_t yyscanner );
+extern int yywrap ( yyscan_t yyscanner );
 #endif
 #endif
 
 /* %not-for-header */
-
 #ifndef YY_NO_UNPUT
     
-    static void yyunput (int c,char *buf_ptr  ,yyscan_t yyscanner);
+    static void yyunput ( int c, char *buf_ptr  , yyscan_t yyscanner);
     
 #endif
 /* %ok-for-header */
@@ -858,21 +1053,20 @@ extern int settings_parser_wrap (yyscan_t yyscanner );
 /* %endif */
 
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
 #endif
 
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
 #endif
 
 #ifndef YY_NO_INPUT
 /* %if-c-only Standard (non-C++) definition */
 /* %not-for-header */
-
 #ifdef __cplusplus
-static int yyinput (yyscan_t yyscanner );
+static int yyinput ( yyscan_t yyscanner );
 #else
-static int input (yyscan_t yyscanner );
+static int input ( yyscan_t yyscanner );
 #endif
 /* %ok-for-header */
 
@@ -881,11 +1075,11 @@ static int input (yyscan_t yyscanner );
 
 /* %if-c-only */
 
-    static void yy_push_state (int _new_state ,yyscan_t yyscanner);
+    static void yy_push_state ( int _new_state , yyscan_t yyscanner);
     
-    static void yy_pop_state (yyscan_t yyscanner );
+    static void yy_pop_state ( yyscan_t yyscanner );
     
-    static int yy_top_state (yyscan_t yyscanner );
+    static int yy_top_state ( yyscan_t yyscanner );
     
 /* %endif */
 
@@ -905,7 +1099,7 @@ static int input (yyscan_t yyscanner );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
 /* %endif */
 /* %if-c++-only C++ definition */
 /* %endif */
@@ -920,7 +1114,7 @@ static int input (yyscan_t yyscanner );
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 		{ \
 		int c = '*'; \
-		size_t n; \
+		int n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -933,7 +1127,7 @@ static int input (yyscan_t yyscanner );
 	else \
 		{ \
 		errno=0; \
-		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+		while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
 			{ \
 			if( errno != EINTR) \
 				{ \
@@ -974,11 +1168,9 @@ static int input (yyscan_t yyscanner );
 
 /* %if-tables-serialization structures and prototypes */
 /* %not-for-header */
-
 /* %ok-for-header */
 
 /* %not-for-header */
-
 /* %tables-yydmap generated elements */
 /* %endif */
 /* end tables serialization structures and prototypes */
@@ -992,10 +1184,10 @@ static int input (yyscan_t yyscanner );
 #define YY_DECL_IS_OURS 1
 /* %if-c-only Standard (non-C++) definition */
 
-extern int settings_parser_lex \
-               (YYSTYPE * yylval_param ,yyscan_t yyscanner);
+extern int yylex \
+               (YYSTYPE * yylval_param , yyscan_t yyscanner);
 
-#define YY_DECL int settings_parser_lex \
+#define YY_DECL int yylex \
                (YYSTYPE * yylval_param , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only C++ definition */
@@ -1019,7 +1211,6 @@ extern int settings_parser_lex \
 	YY_USER_ACTION
 
 /* %not-for-header */
-
 /** The main scanner function which does all the work.
  */
 YY_DECL
@@ -1057,20 +1248,20 @@ YY_DECL
 /* %endif */
 
 		if ( ! YY_CURRENT_BUFFER ) {
-			settings_parser_ensure_buffer_stack (yyscanner);
+			yyensure_buffer_stack (yyscanner);
 			YY_CURRENT_BUFFER_LVALUE =
-				settings_parser__create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+				yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 		}
 
-		settings_parser__load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		}
 
 	{
 /* %% [7.0] user's declarations go here */
-#line 64 "settings/settings_lexer.l"
+#line 69 "settings/settings_lexer.l"
 
 
-#line 1074 "settings/settings_lexer.c"
+#line 1265 "settings/settings_lexer.c"
 
 	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
 		{
@@ -1100,22 +1291,18 @@ yy_match:
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
 				if ( yy_current_state >= 85 )
-					yy_c = yy_meta[(unsigned int) yy_c];
+					yy_c = yy_meta[yy_c];
 				}
-			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 			++yy_cp;
 			}
-		while ( yy_base[yy_current_state] != 335 );
+		while ( yy_current_state != 84 );
+		yy_cp = yyg->yy_last_accepting_cpos;
+		yy_current_state = yyg->yy_last_accepting_state;
 
 yy_find_action:
 /* %% [10.0] code to find the action number goes here */
 		yy_act = yy_accept[yy_current_state];
-		if ( yy_act == 0 )
-			{ /* have to back up */
-			yy_cp = yyg->yy_last_accepting_cpos;
-			yy_current_state = yyg->yy_last_accepting_state;
-			yy_act = yy_accept[yy_current_state];
-			}
 
 		YY_DO_BEFORE_ACTION;
 
@@ -1123,10 +1310,10 @@ yy_find_action:
 
 		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
 			{
-			yy_size_t yyl;
+			int yyl;
 			for ( yyl = 0; yyl < yyleng; ++yyl )
 				if ( yytext[yyl] == '\n' )
-					   
+					
     do{ yylineno++;
         yycolumn=0;
     }while(0)
@@ -1164,40 +1351,40 @@ do_action:	/* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 66 "settings/settings_lexer.l"
+#line 71 "settings/settings_lexer.l"
 /* eat comments */
 	YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 67 "settings/settings_lexer.l"
+#line 72 "settings/settings_lexer.l"
 /* eat whitespace */
 	YY_BREAK
 case 3:
 /* rule 3 can match eol */
 YY_RULE_SETUP
-#line 68 "settings/settings_lexer.l"
+#line 73 "settings/settings_lexer.l"
 /* eat newlines and comments at the end of a line */
 	YY_BREAK
 case 4:
-#line 71 "settings/settings_lexer.l"
+#line 76 "settings/settings_lexer.l"
 case 5:
 YY_RULE_SETUP
-#line 71 "settings/settings_lexer.l"
+#line 76 "settings/settings_lexer.l"
 return yytext[0];
 	YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 73 "settings/settings_lexer.l"
+#line 78 "settings/settings_lexer.l"
 return DOT;
 	YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 74 "settings/settings_lexer.l"
+#line 79 "settings/settings_lexer.l"
 return COMMA;
 	YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 76 "settings/settings_lexer.l"
+#line 81 "settings/settings_lexer.l"
 {
 	yy_push_state(ref, yyscanner);
 	return COLON;
@@ -1205,7 +1392,7 @@ YY_RULE_SETUP
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 81 "settings/settings_lexer.l"
+#line 86 "settings/settings_lexer.l"
 {
 	yy_push_state(val, yyscanner);
 	return yytext[0];
@@ -1218,7 +1405,7 @@ YY_LINENO_REWIND_TO(yy_cp - 1);
 yyg->yy_c_buf_p = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 86 "settings/settings_lexer.l"
+#line 91 "settings/settings_lexer.l"
 {
 	yyextra->string_init(yyextra);
 	yy_push_state(inc, yyscanner);
@@ -1226,7 +1413,7 @@ YY_RULE_SETUP
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 91 "settings/settings_lexer.l"
+#line 96 "settings/settings_lexer.l"
 {
 	PARSER_DBG1(yyextra, "unexpected string detected");
 	return STRING_ERROR;
@@ -1234,7 +1421,7 @@ YY_RULE_SETUP
 	YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 96 "settings/settings_lexer.l"
+#line 101 "settings/settings_lexer.l"
 {
 	yylval->s = strdup(yytext);
 	return NAME;
@@ -1243,28 +1430,28 @@ YY_RULE_SETUP
 
 case 13:
 YY_RULE_SETUP
-#line 102 "settings/settings_lexer.l"
+#line 107 "settings/settings_lexer.l"
 /* eat comments */
 	YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 103 "settings/settings_lexer.l"
+#line 108 "settings/settings_lexer.l"
 /* eat whitespace */
 	YY_BREAK
 case 15:
 /* rule 15 can match eol */
 YY_RULE_SETUP
-#line 104 "settings/settings_lexer.l"
+#line 109 "settings/settings_lexer.l"
 /* eat newlines and comments at the end of a line */
 	YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 106 "settings/settings_lexer.l"
+#line 111 "settings/settings_lexer.l"
 return COMMA;
 	YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 108 "settings/settings_lexer.l"
+#line 113 "settings/settings_lexer.l"
 {
 		yylval->s = strdup(yytext);
 		return NAME;
@@ -1272,7 +1459,7 @@ YY_RULE_SETUP
 	YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 113 "settings/settings_lexer.l"
+#line 118 "settings/settings_lexer.l"
 {
 		unput(yytext[0]);
 		yy_pop_state(yyscanner);
@@ -1282,20 +1469,20 @@ YY_RULE_SETUP
 
 case 19:
 YY_RULE_SETUP
-#line 120 "settings/settings_lexer.l"
+#line 125 "settings/settings_lexer.l"
 /* just ignore these */
 	YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 121 "settings/settings_lexer.l"
+#line 126 "settings/settings_lexer.l"
 
 	YY_BREAK
 case YY_STATE_EOF(val):
-#line 122 "settings/settings_lexer.l"
+#line 127 "settings/settings_lexer.l"
 case 21:
 /* rule 21 can match eol */
 YY_RULE_SETUP
-#line 123 "settings/settings_lexer.l"
+#line 128 "settings/settings_lexer.l"
 {
 		if (*yytext)
 		{
@@ -1319,7 +1506,7 @@ YY_RULE_SETUP
 	YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 144 "settings/settings_lexer.l"
+#line 149 "settings/settings_lexer.l"
 {
 		yyextra->string_init(yyextra);
 		yy_push_state(str, yyscanner);
@@ -1328,7 +1515,7 @@ YY_RULE_SETUP
 /* same as above, but allow more characters */
 case 23:
 YY_RULE_SETUP
-#line 150 "settings/settings_lexer.l"
+#line 155 "settings/settings_lexer.l"
 {
 		yylval->s = strdup(yytext);
 		return NAME;
@@ -1338,16 +1525,16 @@ YY_RULE_SETUP
 
 case 24:
 YY_RULE_SETUP
-#line 157 "settings/settings_lexer.l"
+#line 162 "settings/settings_lexer.l"
 /* just ignore these */
 	YY_BREAK
 /* we allow all characters except #, } and spaces, they can be escaped */
 case YY_STATE_EOF(inc):
-#line 159 "settings/settings_lexer.l"
+#line 164 "settings/settings_lexer.l"
 case 25:
 /* rule 25 can match eol */
 YY_RULE_SETUP
-#line 160 "settings/settings_lexer.l"
+#line 165 "settings/settings_lexer.l"
 {
 		if (*yytext)
 		{
@@ -1371,28 +1558,28 @@ YY_RULE_SETUP
 	YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 180 "settings/settings_lexer.l"
+#line 185 "settings/settings_lexer.l"
 {	/* string include */
 		yy_push_state(str, yyscanner);
 	}
 	YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 183 "settings/settings_lexer.l"
+#line 188 "settings/settings_lexer.l"
 {
 		yyextra->string_add(yyextra, yytext);
 	}
 	YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 186 "settings/settings_lexer.l"
+#line 191 "settings/settings_lexer.l"
 {
 		yyextra->string_add(yyextra, yytext+1);
 	}
 	YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 189 "settings/settings_lexer.l"
+#line 194 "settings/settings_lexer.l"
 {
 		yyextra->string_add(yyextra, yytext);
 	}
@@ -1401,17 +1588,17 @@ YY_RULE_SETUP
 
 case 30:
 YY_RULE_SETUP
-#line 195 "settings/settings_lexer.l"
+#line 200 "settings/settings_lexer.l"
 /* just ignore these */
 	YY_BREAK
 case 31:
-#line 197 "settings/settings_lexer.l"
+#line 202 "settings/settings_lexer.l"
 YY_RULE_SETUP
 case YY_STATE_EOF(str):
-#line 197 "settings/settings_lexer.l"
+#line 202 "settings/settings_lexer.l"
 case 32:
 YY_RULE_SETUP
-#line 198 "settings/settings_lexer.l"
+#line 203 "settings/settings_lexer.l"
 {
 		if (!streq(yytext, "\""))
 		{
@@ -1434,34 +1621,34 @@ YY_RULE_SETUP
 	YY_BREAK
 case 33:
 YY_RULE_SETUP
-#line 218 "settings/settings_lexer.l"
+#line 223 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, "\n");
 	YY_BREAK
 case 34:
 YY_RULE_SETUP
-#line 219 "settings/settings_lexer.l"
+#line 224 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, "\r");
 	YY_BREAK
 case 35:
 YY_RULE_SETUP
-#line 220 "settings/settings_lexer.l"
+#line 225 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, "\t");
 	YY_BREAK
 case 36:
 /* rule 36 can match eol */
 YY_RULE_SETUP
-#line 221 "settings/settings_lexer.l"
+#line 226 "settings/settings_lexer.l"
 /* merge lines that end with escaped EOL characters */
 	YY_BREAK
 case 37:
 YY_RULE_SETUP
-#line 222 "settings/settings_lexer.l"
+#line 227 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, yytext+1);
 	YY_BREAK
 case 38:
 /* rule 38 can match eol */
 YY_RULE_SETUP
-#line 223 "settings/settings_lexer.l"
+#line 228 "settings/settings_lexer.l"
 {
 		yyextra->string_add(yyextra, yytext);
 	}
@@ -1469,7 +1656,7 @@ YY_RULE_SETUP
 
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(ref):
-#line 228 "settings/settings_lexer.l"
+#line 233 "settings/settings_lexer.l"
 {
 	settings_parser_pop_buffer_state(yyscanner);
 	if (!settings_parser_open_next_file(yyextra) && !YY_CURRENT_BUFFER)
@@ -1480,10 +1667,10 @@ case YY_STATE_EOF(ref):
 	YY_BREAK
 case 39:
 YY_RULE_SETUP
-#line 236 "settings/settings_lexer.l"
+#line 241 "settings/settings_lexer.l"
 YY_FATAL_ERROR( "flex scanner jammed" );
 	YY_BREAK
-#line 1487 "settings/settings_lexer.c"
+#line 1674 "settings/settings_lexer.c"
 
 	case YY_END_OF_BUFFER:
 		{
@@ -1499,7 +1686,7 @@ YY_FATAL_ERROR( "flex scanner jammed" );
 			/* We're scanning a new file or input source.  It's
 			 * possible that this happened because the user
 			 * just pointed yyin at a new source and called
-			 * settings_parser_lex().  If so, then we have to assure
+			 * yylex().  If so, then we have to assure
 			 * consistency between YY_CURRENT_BUFFER and our
 			 * globals.  Here is the right place to do so, because
 			 * this is the first action (other than possibly a
@@ -1553,7 +1740,8 @@ YY_FATAL_ERROR( "flex scanner jammed" );
 			else
 				{
 /* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */
-				yy_cp = yyg->yy_c_buf_p;
+				yy_cp = yyg->yy_last_accepting_cpos;
+				yy_current_state = yyg->yy_last_accepting_state;
 				goto yy_find_action;
 				}
 			}
@@ -1564,7 +1752,7 @@ YY_FATAL_ERROR( "flex scanner jammed" );
 				{
 				yyg->yy_did_buffer_switch_on_eof = 0;
 
-				if ( settings_parser_wrap(yyscanner ) )
+				if ( yywrap( yyscanner ) )
 					{
 					/* Note: because we've taken care in
 					 * yy_get_next_buffer() to have set up
@@ -1618,12 +1806,11 @@ YY_FATAL_ERROR( "flex scanner jammed" );
 	} /* end of action switch */
 		} /* end of scanning one token */
 	} /* end of user's declarations */
-} /* end of settings_parser_lex */
+} /* end of yylex */
 /* %ok-for-header */
 
 /* %if-c++-only */
 /* %not-for-header */
-
 /* %ok-for-header */
 
 /* %endif */
@@ -1644,7 +1831,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
 	char *source = yyg->yytext_ptr;
-	yy_size_t number_to_move, i;
+	int number_to_move, i;
 	int ret_val;
 
 	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
@@ -1673,7 +1860,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	/* Try to read more data. */
 
 	/* First move last chars to start of buffer. */
-	number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
 
 	for ( i = 0; i < number_to_move; ++i )
 		*(dest++) = *(source++);
@@ -1686,7 +1873,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 	else
 		{
-			yy_size_t num_to_read =
+			int num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
@@ -1700,7 +1887,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 			if ( b->yy_is_our_buffer )
 				{
-				yy_size_t new_size = b->yy_buf_size * 2;
+				int new_size = b->yy_buf_size * 2;
 
 				if ( new_size <= 0 )
 					b->yy_buf_size += b->yy_buf_size / 8;
@@ -1709,11 +1896,12 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 				b->yy_ch_buf = (char *)
 					/* Include room in for 2 EOB chars. */
-					settings_parser_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+					yyrealloc( (void *) b->yy_ch_buf,
+							 (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
 				}
 			else
 				/* Can't grow it, we don't own it. */
-				b->yy_ch_buf = 0;
+				b->yy_ch_buf = NULL;
 
 			if ( ! b->yy_ch_buf )
 				YY_FATAL_ERROR(
@@ -1741,7 +1929,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		if ( number_to_move == YY_MORE_ADJ )
 			{
 			ret_val = EOB_ACT_END_OF_FILE;
-			settings_parser_restart(yyin  ,yyscanner);
+			yyrestart( yyin  , yyscanner);
 			}
 
 		else
@@ -1755,12 +1943,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	else
 		ret_val = EOB_ACT_CONTINUE_SCAN;
 
-	if ((int) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+	if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
 		/* Extend the array by 50%, plus the number we really need. */
 		int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
-		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) settings_parser_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+			(void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
 		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
 			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+		/* "- 2" to take care of EOB's */
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
 	}
 
 	yyg->yy_n_chars += number_to_move;
@@ -1776,7 +1967,6 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 /* %if-c-only */
 /* %not-for-header */
-
     static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
@@ -1802,9 +1992,9 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
 			if ( yy_current_state >= 85 )
-				yy_c = yy_meta[(unsigned int) yy_c];
+				yy_c = yy_meta[yy_c];
 			}
-		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 		}
 
 	return yy_current_state;
@@ -1836,9 +2026,9 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
 		if ( yy_current_state >= 85 )
-			yy_c = yy_meta[(unsigned int) yy_c];
+			yy_c = yy_meta[yy_c];
 		}
-	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 	yy_is_jam = (yy_current_state == 84);
 
 	(void)yyg;
@@ -1864,7 +2054,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
 		{ /* need to shift things up to make room */
 		/* +2 for EOB chars. */
-		yy_size_t number_to_move = yyg->yy_n_chars + 2;
+		int number_to_move = yyg->yy_n_chars + 2;
 		char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
 					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
 		char *source =
@@ -1876,7 +2066,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		yy_cp += (int) (dest - source);
 		yy_bp += (int) (dest - source);
 		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
-			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+			yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
 
 		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
 			YY_FATAL_ERROR( "flex scanner push-back overflow" );
@@ -1928,7 +2118,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 		else
 			{ /* need more input */
-			yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
 			++yyg->yy_c_buf_p;
 
 			switch ( yy_get_next_buffer( yyscanner ) )
@@ -1945,14 +2135,14 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 					 */
 
 					/* Reset buffer status. */
-					settings_parser_restart(yyin ,yyscanner);
+					yyrestart( yyin , yyscanner);
 
 					/*FALLTHROUGH*/
 
 				case EOB_ACT_END_OF_FILE:
 					{
-					if ( settings_parser_wrap(yyscanner ) )
-						return EOF;
+					if ( yywrap( yyscanner ) )
+						return 0;
 
 					if ( ! yyg->yy_did_buffer_switch_on_eof )
 						YY_NEW_FILE;
@@ -1976,7 +2166,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 /* %% [19.0] update BOL and yylineno */
 	if ( c == '\n' )
-		   
+		
     do{ yylineno++;
         yycolumn=0;
     }while(0)
@@ -1994,7 +2184,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
  * @note This function does not reset the start condition to @c INITIAL .
  */
 /* %if-c-only */
-    void settings_parser_restart  (FILE * input_file , yyscan_t yyscanner)
+    void yyrestart  (FILE * input_file , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2002,13 +2192,13 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
 	if ( ! YY_CURRENT_BUFFER ){
-        settings_parser_ensure_buffer_stack (yyscanner);
+        yyensure_buffer_stack (yyscanner);
 		YY_CURRENT_BUFFER_LVALUE =
-            settings_parser__create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 	}
 
-	settings_parser__init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
-	settings_parser__load_buffer_state(yyscanner );
+	yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+	yy_load_buffer_state( yyscanner );
 }
 
 /* %if-c++-only */
@@ -2019,7 +2209,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  */
 /* %if-c-only */
-    void settings_parser__switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2028,10 +2218,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 	/* TODO. We should be able to replace this entire function body
 	 * with
-	 *		settings_parser_pop_buffer_state();
-	 *		settings_parser_push_buffer_state(new_buffer);
+	 *		yypop_buffer_state();
+	 *		yypush_buffer_state(new_buffer);
      */
-	settings_parser_ensure_buffer_stack (yyscanner);
+	yyensure_buffer_stack (yyscanner);
 	if ( YY_CURRENT_BUFFER == new_buffer )
 		return;
 
@@ -2044,18 +2234,18 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		}
 
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
-	settings_parser__load_buffer_state(yyscanner );
+	yy_load_buffer_state( yyscanner );
 
 	/* We don't actually know whether we did this switch during
-	 * EOF (settings_parser_wrap()) processing, but the only time this flag
-	 * is looked at is after settings_parser_wrap() is called, so it's safe
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
 	 * to go ahead and always set it.
 	 */
 	yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
 /* %if-c-only */
-static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
+static void yy_load_buffer_state  (yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2078,29 +2268,29 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
  * @return the allocated buffer state.
  */
 /* %if-c-only */
-    YY_BUFFER_STATE settings_parser__create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
 {
 	YY_BUFFER_STATE b;
     
-	b = (YY_BUFFER_STATE) settings_parser_alloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in settings_parser__create_buffer()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
-	b->yy_buf_size = (yy_size_t)size;
+	b->yy_buf_size = size;
 
 	/* yy_ch_buf has to be 2 characters longer than the size given because
 	 * we need to put in 2 end-of-buffer characters.
 	 */
-	b->yy_ch_buf = (char *) settings_parser_alloc(b->yy_buf_size + 2 ,yyscanner );
+	b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
 	if ( ! b->yy_ch_buf )
-		YY_FATAL_ERROR( "out of dynamic memory in settings_parser__create_buffer()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
 	b->yy_is_our_buffer = 1;
 
-	settings_parser__init_buffer(b,file ,yyscanner);
+	yy_init_buffer( b, file , yyscanner);
 
 	return b;
 }
@@ -2109,11 +2299,11 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
 /* %endif */
 
 /** Destroy the buffer.
- * @param b a buffer created with settings_parser__create_buffer()
+ * @param b a buffer created with yy_create_buffer()
  * @param yyscanner The scanner object.
  */
 /* %if-c-only */
-    void settings_parser__delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+    void yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2127,17 +2317,17 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
 		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
 
 	if ( b->yy_is_our_buffer )
-		settings_parser_free((void *) b->yy_ch_buf ,yyscanner );
+		yyfree( (void *) b->yy_ch_buf , yyscanner );
 
-	settings_parser_free((void *) b ,yyscanner );
+	yyfree( (void *) b , yyscanner );
 }
 
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
- * such as during a settings_parser_restart() or at EOF.
+ * such as during a yyrestart() or at EOF.
  */
 /* %if-c-only */
-    static void settings_parser__init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2146,7 +2336,7 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
 	int oerrno = errno;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-	settings_parser__flush_buffer(b ,yyscanner);
+	yy_flush_buffer( b , yyscanner);
 
 /* %if-c-only */
 	b->yy_input_file = file;
@@ -2155,8 +2345,8 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
 /* %endif */
 	b->yy_fill_buffer = 1;
 
-    /* If b is the current buffer, then settings_parser__init_buffer was _probably_
-     * called from settings_parser_restart() or through yy_get_next_buffer.
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
      * In that case, we don't want to reset the lineno or column.
      */
     if (b != YY_CURRENT_BUFFER){
@@ -2166,7 +2356,7 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
 
 /* %if-c-only */
 
-        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+        b->yy_is_interactive = 0;
     
 /* %endif */
 /* %if-c++-only */
@@ -2179,7 +2369,7 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  */
 /* %if-c-only */
-    void settings_parser__flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+    void yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2203,7 +2393,7 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
 	if ( b == YY_CURRENT_BUFFER )
-		settings_parser__load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 }
 
 /* %if-c-or-c++ */
@@ -2214,7 +2404,7 @@ static void settings_parser__load_buffer_state  (yyscan_t yyscanner)
  *  @param yyscanner The scanner object.
  */
 /* %if-c-only */
-void settings_parser_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2223,9 +2413,9 @@ void settings_parser_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yy
 	if (new_buffer == NULL)
 		return;
 
-	settings_parser_ensure_buffer_stack(yyscanner);
+	yyensure_buffer_stack(yyscanner);
 
-	/* This block is copied from settings_parser__switch_to_buffer. */
+	/* This block is copied from yy_switch_to_buffer. */
 	if ( YY_CURRENT_BUFFER )
 		{
 		/* Flush out information for old buffer. */
@@ -2239,8 +2429,8 @@ void settings_parser_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yy
 		yyg->yy_buffer_stack_top++;
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
 
-	/* copied from settings_parser__switch_to_buffer. */
-	settings_parser__load_buffer_state(yyscanner );
+	/* copied from yy_switch_to_buffer. */
+	yy_load_buffer_state( yyscanner );
 	yyg->yy_did_buffer_switch_on_eof = 1;
 }
 /* %endif */
@@ -2251,7 +2441,7 @@ void settings_parser_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yy
  *  @param yyscanner The scanner object.
  */
 /* %if-c-only */
-void settings_parser_pop_buffer_state (yyscan_t yyscanner)
+void yypop_buffer_state (yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2260,13 +2450,13 @@ void settings_parser_pop_buffer_state (yyscan_t yyscanner)
 	if (!YY_CURRENT_BUFFER)
 		return;
 
-	settings_parser__delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
 	YY_CURRENT_BUFFER_LVALUE = NULL;
 	if (yyg->yy_buffer_stack_top > 0)
 		--yyg->yy_buffer_stack_top;
 
 	if (YY_CURRENT_BUFFER) {
-		settings_parser__load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		yyg->yy_did_buffer_switch_on_eof = 1;
 	}
 }
@@ -2277,7 +2467,7 @@ void settings_parser_pop_buffer_state (yyscan_t yyscanner)
  *  Guarantees space for at least one push.
  */
 /* %if-c-only */
-static void settings_parser_ensure_buffer_stack (yyscan_t yyscanner)
+static void yyensure_buffer_stack (yyscan_t yyscanner)
 /* %endif */
 /* %if-c++-only */
 /* %endif */
@@ -2291,15 +2481,15 @@ static void settings_parser_ensure_buffer_stack (yyscan_t yyscanner)
 		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
 		 * immediate realloc on the next call.
          */
-		num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
-		yyg->yy_buffer_stack = (struct yy_buffer_state**)settings_parser_alloc
+      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
 								(num_to_alloc * sizeof(struct yy_buffer_state*)
 								, yyscanner);
 		if ( ! yyg->yy_buffer_stack )
-			YY_FATAL_ERROR( "out of dynamic memory in settings_parser_ensure_buffer_stack()" );
-								  
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
 		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-				
+
 		yyg->yy_buffer_stack_max = num_to_alloc;
 		yyg->yy_buffer_stack_top = 0;
 		return;
@@ -2311,12 +2501,12 @@ static void settings_parser_ensure_buffer_stack (yyscan_t yyscanner)
 		yy_size_t grow_size = 8 /* arbitrary grow size */;
 
 		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
-		yyg->yy_buffer_stack = (struct yy_buffer_state**)settings_parser_realloc
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
 								(yyg->yy_buffer_stack,
 								num_to_alloc * sizeof(struct yy_buffer_state*)
 								, yyscanner);
 		if ( ! yyg->yy_buffer_stack )
-			YY_FATAL_ERROR( "out of dynamic memory in settings_parser_ensure_buffer_stack()" );
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
 
 		/* zero only the new slots.*/
 		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
@@ -2330,9 +2520,9 @@ static void settings_parser_ensure_buffer_stack (yyscan_t yyscanner)
  * @param base the character buffer
  * @param size the size in bytes of the character buffer
  * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object. 
+ * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE settings_parser__scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
     
@@ -2340,73 +2530,73 @@ YY_BUFFER_STATE settings_parser__scan_buffer  (char * base, yy_size_t  size , yy
 	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
 	     base[size-1] != YY_END_OF_BUFFER_CHAR )
 		/* They forgot to leave room for the EOB's. */
-		return 0;
+		return NULL;
 
-	b = (YY_BUFFER_STATE) settings_parser_alloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in settings_parser__scan_buffer()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
 
-	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_size = (int) (size - 2);	/* "- 2" to take care of EOB's */
 	b->yy_buf_pos = b->yy_ch_buf = base;
 	b->yy_is_our_buffer = 0;
-	b->yy_input_file = 0;
+	b->yy_input_file = NULL;
 	b->yy_n_chars = b->yy_buf_size;
 	b->yy_is_interactive = 0;
 	b->yy_at_bol = 1;
 	b->yy_fill_buffer = 0;
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
-	settings_parser__switch_to_buffer(b ,yyscanner );
+	yy_switch_to_buffer( b , yyscanner );
 
 	return b;
 }
 /* %endif */
 
 /* %if-c-only */
-/** Setup the input buffer state to scan a string. The next call to settings_parser_lex() will
+/** Setup the input buffer state to scan a string. The next call to yylex() will
  * scan from a @e copy of @a str.
  * @param yystr a NUL-terminated string to scan
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  * @note If you want to scan bytes that may contain NUL values, then use
- *       settings_parser__scan_bytes() instead.
+ *       yy_scan_bytes() instead.
  */
-YY_BUFFER_STATE settings_parser__scan_string (yyconst char * yystr , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
 {
     
-	return settings_parser__scan_bytes(yystr,strlen(yystr) ,yyscanner);
+	return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
 }
 /* %endif */
 
 /* %if-c-only */
-/** Setup the input buffer state to scan the given bytes. The next call to settings_parser_lex() will
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
  * scan from a @e copy of @a bytes.
  * @param yybytes the byte buffer to scan
  * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE settings_parser__scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_bytes  (const char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
 	char *buf;
 	yy_size_t n;
-	yy_size_t i;
+	int i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = _yybytes_len + 2;
-	buf = (char *) settings_parser_alloc(n ,yyscanner );
+	n = (yy_size_t) (_yybytes_len + 2);
+	buf = (char *) yyalloc( n , yyscanner );
 	if ( ! buf )
-		YY_FATAL_ERROR( "out of dynamic memory in settings_parser__scan_bytes()" );
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
 
 	for ( i = 0; i < _yybytes_len; ++i )
 		buf[i] = yybytes[i];
 
 	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
-	b = settings_parser__scan_buffer(buf,n ,yyscanner);
+	b = yy_scan_buffer( buf, n , yyscanner);
 	if ( ! b )
-		YY_FATAL_ERROR( "bad buffer in settings_parser__scan_bytes()" );
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
 
 	/* It's okay to grow etc. this buffer, and we should throw it
 	 * away when we're done.
@@ -2429,13 +2619,14 @@ YY_BUFFER_STATE settings_parser__scan_bytes  (yyconst char * yybytes, yy_size_t
 		yy_size_t new_size;
 
 		yyg->yy_start_stack_depth += YY_START_STACK_INCR;
-		new_size = yyg->yy_start_stack_depth * sizeof( int );
+		new_size = (yy_size_t) yyg->yy_start_stack_depth * sizeof( int );
 
 		if ( ! yyg->yy_start_stack )
-			yyg->yy_start_stack = (int *) settings_parser_alloc(new_size ,yyscanner );
+			yyg->yy_start_stack = (int *) yyalloc( new_size , yyscanner );
 
 		else
-			yyg->yy_start_stack = (int *) settings_parser_realloc((void *) yyg->yy_start_stack,new_size ,yyscanner );
+			yyg->yy_start_stack = (int *) yyrealloc(
+					(void *) yyg->yy_start_stack, new_size , yyscanner );
 
 		if ( ! yyg->yy_start_stack )
 			YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
@@ -2474,11 +2665,11 @@ YY_BUFFER_STATE settings_parser__scan_bytes  (yyconst char * yybytes, yy_size_t
 #endif
 
 /* %if-c-only */
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	(void) fprintf( stderr, "%s\n", msg );
+	fprintf( stderr, "%s\n", msg );
 	exit( YY_EXIT_FAILURE );
 }
 /* %endif */
@@ -2510,7 +2701,7 @@ static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
 /** Get the user-defined data for this scanner.
  * @param yyscanner The scanner object.
  */
-YY_EXTRA_TYPE settings_parser_get_extra  (yyscan_t yyscanner)
+YY_EXTRA_TYPE yyget_extra  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyextra;
@@ -2521,10 +2712,10 @@ YY_EXTRA_TYPE settings_parser_get_extra  (yyscan_t yyscanner)
 /** Get the current line number.
  * @param yyscanner The scanner object.
  */
-int settings_parser_get_lineno  (yyscan_t yyscanner)
+int yyget_lineno  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    
+
         if (! YY_CURRENT_BUFFER)
             return 0;
     
@@ -2534,10 +2725,10 @@ int settings_parser_get_lineno  (yyscan_t yyscanner)
 /** Get the current column number.
  * @param yyscanner The scanner object.
  */
-int settings_parser_get_column  (yyscan_t yyscanner)
+int yyget_column  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    
+
         if (! YY_CURRENT_BUFFER)
             return 0;
     
@@ -2547,7 +2738,7 @@ int settings_parser_get_column  (yyscan_t yyscanner)
 /** Get the input stream.
  * @param yyscanner The scanner object.
  */
-FILE *settings_parser_get_in  (yyscan_t yyscanner)
+FILE *yyget_in  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyin;
@@ -2556,7 +2747,7 @@ FILE *settings_parser_get_in  (yyscan_t yyscanner)
 /** Get the output stream.
  * @param yyscanner The scanner object.
  */
-FILE *settings_parser_get_out  (yyscan_t yyscanner)
+FILE *yyget_out  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyout;
@@ -2565,7 +2756,7 @@ FILE *settings_parser_get_out  (yyscan_t yyscanner)
 /** Get the length of the current token.
  * @param yyscanner The scanner object.
  */
-yy_size_t settings_parser_get_leng  (yyscan_t yyscanner)
+int yyget_leng  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyleng;
@@ -2575,7 +2766,7 @@ yy_size_t settings_parser_get_leng  (yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  */
 
-char *settings_parser_get_text  (yyscan_t yyscanner)
+char *yyget_text  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yytext;
@@ -2587,7 +2778,7 @@ char *settings_parser_get_text  (yyscan_t yyscanner)
  * @param user_defined The data to be associated with this scanner.
  * @param yyscanner The scanner object.
  */
-void settings_parser_set_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+void yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyextra = user_defined ;
@@ -2599,13 +2790,13 @@ void settings_parser_set_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner
  * @param _line_number line number
  * @param yyscanner The scanner object.
  */
-void settings_parser_set_lineno (int  _line_number , yyscan_t yyscanner)
+void yyset_lineno (int  _line_number , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
         /* lineno is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           YY_FATAL_ERROR( "settings_parser_set_lineno called with no buffer" );
+           YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
     
     yylineno = _line_number;
 }
@@ -2614,13 +2805,13 @@ void settings_parser_set_lineno (int  _line_number , yyscan_t yyscanner)
  * @param _column_no column number
  * @param yyscanner The scanner object.
  */
-void settings_parser_set_column (int  _column_no , yyscan_t yyscanner)
+void yyset_column (int  _column_no , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
         /* column is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           YY_FATAL_ERROR( "settings_parser_set_column called with no buffer" );
+           YY_FATAL_ERROR( "yyset_column called with no buffer" );
     
     yycolumn = _column_no;
 }
@@ -2629,27 +2820,27 @@ void settings_parser_set_column (int  _column_no , yyscan_t yyscanner)
  * input buffer.
  * @param _in_str A readable stream.
  * @param yyscanner The scanner object.
- * @see settings_parser__switch_to_buffer
+ * @see yy_switch_to_buffer
  */
-void settings_parser_set_in (FILE *  _in_str , yyscan_t yyscanner)
+void yyset_in (FILE *  _in_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyin = _in_str ;
 }
 
-void settings_parser_set_out (FILE *  _out_str , yyscan_t yyscanner)
+void yyset_out (FILE *  _out_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyout = _out_str ;
 }
 
-int settings_parser_get_debug  (yyscan_t yyscanner)
+int yyget_debug  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yy_flex_debug;
 }
 
-void settings_parser_set_debug (int  _bdebug , yyscan_t yyscanner)
+void yyset_debug (int  _bdebug , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yy_flex_debug = _bdebug ;
@@ -2662,13 +2853,13 @@ void settings_parser_set_debug (int  _bdebug , yyscan_t yyscanner)
 
 /* %if-bison-bridge */
 
-YYSTYPE * settings_parser_get_lval  (yyscan_t yyscanner)
+YYSTYPE * yyget_lval  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yylval;
 }
 
-void settings_parser_set_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+void yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yylval = yylval_param;
@@ -2678,20 +2869,18 @@ void settings_parser_set_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
 
 /* User-visible API */
 
-/* settings_parser_lex_init is special because it creates the scanner itself, so it is
+/* yylex_init is special because it creates the scanner itself, so it is
  * the ONLY reentrant function that doesn't take the scanner as the last argument.
  * That's why we explicitly handle the declaration, instead of using our macros.
  */
-
-int settings_parser_lex_init(yyscan_t* ptr_yy_globals)
-
+int yylex_init(yyscan_t* ptr_yy_globals)
 {
     if (ptr_yy_globals == NULL){
         errno = EINVAL;
         return 1;
     }
 
-    *ptr_yy_globals = (yyscan_t) settings_parser_alloc ( sizeof( struct yyguts_t ), NULL );
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
 
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
@@ -2704,39 +2893,37 @@ int settings_parser_lex_init(yyscan_t* ptr_yy_globals)
     return yy_init_globals ( *ptr_yy_globals );
 }
 
-/* settings_parser_lex_init_extra has the same functionality as settings_parser_lex_init, but follows the
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
  * convention of taking the scanner as the last argument. Note however, that
  * this is a *pointer* to a scanner, as it will be allocated by this call (and
  * is the reason, too, why this function also must handle its own declaration).
- * The user defined value in the first argument will be available to settings_parser_alloc in
+ * The user defined value in the first argument will be available to yyalloc in
  * the yyextra field.
  */
-
-int settings_parser_lex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
-
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
 {
     struct yyguts_t dummy_yyguts;
 
-    settings_parser_set_extra (yy_user_defined, &dummy_yyguts);
+    yyset_extra (yy_user_defined, &dummy_yyguts);
 
     if (ptr_yy_globals == NULL){
         errno = EINVAL;
         return 1;
     }
-	
-    *ptr_yy_globals = (yyscan_t) settings_parser_alloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-	
+
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
         return 1;
     }
-    
+
     /* By setting to 0xAA, we expose bugs in
     yy_init_globals. Leave at 0x00 for releases. */
     memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-    
-    settings_parser_set_extra (yy_user_defined, *ptr_yy_globals);
-    
+
+    yyset_extra (yy_user_defined, *ptr_yy_globals);
+
     return yy_init_globals ( *ptr_yy_globals );
 }
 
@@ -2747,13 +2934,13 @@ static int yy_init_globals (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     /* Initialization is the same as for the non-reentrant scanner.
-     * This function is called from settings_parser_lex_destroy(), so don't allocate here.
+     * This function is called from yylex_destroy(), so don't allocate here.
      */
 
-    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack = NULL;
     yyg->yy_buffer_stack_top = 0;
     yyg->yy_buffer_stack_max = 0;
-    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_c_buf_p = NULL;
     yyg->yy_init = 0;
     yyg->yy_start = 0;
 
@@ -2766,45 +2953,45 @@ static int yy_init_globals (yyscan_t yyscanner)
     yyin = stdin;
     yyout = stdout;
 #else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
+    yyin = NULL;
+    yyout = NULL;
 #endif
 
     /* For future reference: Set errno on error, since we are called by
-     * settings_parser_lex_init()
+     * yylex_init()
      */
     return 0;
 }
 /* %endif */
 
 /* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */
-/* settings_parser_lex_destroy is for both reentrant and non-reentrant scanners. */
-int settings_parser_lex_destroy  (yyscan_t yyscanner)
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
     /* Pop the buffer stack, destroying each element. */
 	while(YY_CURRENT_BUFFER){
-		settings_parser__delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
 		YY_CURRENT_BUFFER_LVALUE = NULL;
-		settings_parser_pop_buffer_state(yyscanner);
+		yypop_buffer_state(yyscanner);
 	}
 
 	/* Destroy the stack itself. */
-	settings_parser_free(yyg->yy_buffer_stack ,yyscanner);
+	yyfree(yyg->yy_buffer_stack , yyscanner);
 	yyg->yy_buffer_stack = NULL;
 
     /* Destroy the start condition stack. */
-        settings_parser_free(yyg->yy_start_stack ,yyscanner );
+        yyfree( yyg->yy_start_stack , yyscanner );
         yyg->yy_start_stack = NULL;
 
     /* Reset the globals. This is important in a non-reentrant scanner so the next time
-     * settings_parser_lex() is called, initialization will occur. */
+     * yylex() is called, initialization will occur. */
     yy_init_globals( yyscanner);
 
 /* %if-reentrant */
     /* Destroy the main struct (reentrant only). */
-    settings_parser_free ( yyscanner , yyscanner );
+    yyfree ( yyscanner , yyscanner );
     yyscanner = NULL;
 /* %endif */
     return 0;
@@ -2816,7 +3003,7 @@ int settings_parser_lex_destroy  (yyscan_t yyscanner)
  */
 
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
@@ -2828,7 +3015,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca
 #endif
 
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
 {
 	int n;
 	for ( n = 0; s[n]; ++n )
@@ -2838,14 +3025,14 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
 }
 #endif
 
-void *settings_parser_alloc (yy_size_t  size , yyscan_t yyscanner)
+void *yyalloc (yy_size_t  size , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	return (void *) malloc( size );
+	return malloc(size);
 }
 
-void *settings_parser_realloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+void *yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
@@ -2857,14 +3044,14 @@ void *settings_parser_realloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner
 	 * any pointer type to void*, and deal with argument conversions
 	 * as though doing an assignment.
 	 */
-	return (void *) realloc( (char *) ptr, size );
+	return realloc(ptr, size);
 }
 
-void settings_parser_free (void * ptr , yyscan_t yyscanner)
+void yyfree (void * ptr , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	free( (char *) ptr );	/* see settings_parser_realloc() for (char *) cast */
+	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
 }
 
 /* %if-tables-serialization definitions */
@@ -2874,8 +3061,7 @@ void settings_parser_free (void * ptr , yyscan_t yyscanner)
 
 /* %ok-for-header */
 
-#line 236 "settings/settings_lexer.l"
-
+#line 241 "settings/settings_lexer.l"
 
 
 /**
diff --git a/src/libstrongswan/settings/settings_lexer.l b/src/libstrongswan/settings/settings_lexer.l
index 19ab8d7b2..e8c2b9884 100644
--- a/src/libstrongswan/settings/settings_lexer.l
+++ b/src/libstrongswan/settings/settings_lexer.l
@@ -32,6 +32,11 @@ static void include_files(parser_helper_t *ctx);
 /* do not declare unneeded functions */
 %option noinput noyywrap
 
+/* do not include unistd.h as it might conflict with our scanner states */
+%option nounistd
+/* due to that disable interactive mode, which requires isatty() */
+%option never-interactive
+
 /* don't use global variables, and interact properly with bison */
 %option reentrant bison-bridge
 
diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am
index 5737e7a17..d4cac5a3b 100644
--- a/src/libstrongswan/tests/Makefile.am
+++ b/src/libstrongswan/tests/Makefile.am
@@ -58,6 +58,7 @@ libstrongswan_tests_SOURCES = tests.h tests.c \
   suites/test_mgf1.c \
   suites/test_ntru.c \
   suites/test_ed25519.c \
+  suites/test_ed448.c \
   suites/test_signature_params.c
 
 libstrongswan_tests_CFLAGS = \
diff --git a/src/libstrongswan/tests/Makefile.in b/src/libstrongswan/tests/Makefile.in
index c5b943572..664c84f3f 100644
--- a/src/libstrongswan/tests/Makefile.in
+++ b/src/libstrongswan/tests/Makefile.in
@@ -163,6 +163,7 @@ am_libstrongswan_tests_OBJECTS = libstrongswan_tests-tests.$(OBJEXT) \
 	suites/libstrongswan_tests-test_mgf1.$(OBJEXT) \
 	suites/libstrongswan_tests-test_ntru.$(OBJEXT) \
 	suites/libstrongswan_tests-test_ed25519.$(OBJEXT) \
+	suites/libstrongswan_tests-test_ed448.$(OBJEXT) \
 	suites/libstrongswan_tests-test_signature_params.$(OBJEXT)
 libstrongswan_tests_OBJECTS = $(am_libstrongswan_tests_OBJECTS)
 libstrongswan_tests_DEPENDENCIES =  \
@@ -548,6 +549,7 @@ libstrongswan_tests_SOURCES = tests.h tests.c \
   suites/test_mgf1.c \
   suites/test_ntru.c \
   suites/test_ed25519.c \
+  suites/test_ed448.c \
   suites/test_signature_params.c
 
 libstrongswan_tests_CFLAGS = \
@@ -708,6 +710,8 @@ suites/libstrongswan_tests-test_ntru.$(OBJEXT):  \
 	suites/$(am__dirstamp) suites/$(DEPDIR)/$(am__dirstamp)
 suites/libstrongswan_tests-test_ed25519.$(OBJEXT):  \
 	suites/$(am__dirstamp) suites/$(DEPDIR)/$(am__dirstamp)
+suites/libstrongswan_tests-test_ed448.$(OBJEXT):  \
+	suites/$(am__dirstamp) suites/$(DEPDIR)/$(am__dirstamp)
 suites/libstrongswan_tests-test_signature_params.$(OBJEXT):  \
 	suites/$(am__dirstamp) suites/$(DEPDIR)/$(am__dirstamp)
 
@@ -740,6 +744,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/libstrongswan_tests-test_crypto_factory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/libstrongswan_tests-test_ecdsa.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/libstrongswan_tests-test_ed25519.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/libstrongswan_tests-test_ed448.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/libstrongswan_tests-test_enum.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/libstrongswan_tests-test_enumerator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/libstrongswan_tests-test_fetch_http.Po@am__quote@
@@ -1359,6 +1364,20 @@ suites/libstrongswan_tests-test_ed25519.obj: suites/test_ed25519.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libstrongswan_tests_CFLAGS) $(CFLAGS) -c -o suites/libstrongswan_tests-test_ed25519.obj `if test -f 'suites/test_ed25519.c'; then $(CYGPATH_W) 'suites/test_ed25519.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_ed25519.c'; fi`
 
+suites/libstrongswan_tests-test_ed448.o: suites/test_ed448.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libstrongswan_tests_CFLAGS) $(CFLAGS) -MT suites/libstrongswan_tests-test_ed448.o -MD -MP -MF suites/$(DEPDIR)/libstrongswan_tests-test_ed448.Tpo -c -o suites/libstrongswan_tests-test_ed448.o `test -f 'suites/test_ed448.c' || echo '$(srcdir)/'`suites/test_ed448.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libstrongswan_tests-test_ed448.Tpo suites/$(DEPDIR)/libstrongswan_tests-test_ed448.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_ed448.c' object='suites/libstrongswan_tests-test_ed448.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libstrongswan_tests_CFLAGS) $(CFLAGS) -c -o suites/libstrongswan_tests-test_ed448.o `test -f 'suites/test_ed448.c' || echo '$(srcdir)/'`suites/test_ed448.c
+
+suites/libstrongswan_tests-test_ed448.obj: suites/test_ed448.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libstrongswan_tests_CFLAGS) $(CFLAGS) -MT suites/libstrongswan_tests-test_ed448.obj -MD -MP -MF suites/$(DEPDIR)/libstrongswan_tests-test_ed448.Tpo -c -o suites/libstrongswan_tests-test_ed448.obj `if test -f 'suites/test_ed448.c'; then $(CYGPATH_W) 'suites/test_ed448.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_ed448.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libstrongswan_tests-test_ed448.Tpo suites/$(DEPDIR)/libstrongswan_tests-test_ed448.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_ed448.c' object='suites/libstrongswan_tests-test_ed448.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libstrongswan_tests_CFLAGS) $(CFLAGS) -c -o suites/libstrongswan_tests-test_ed448.obj `if test -f 'suites/test_ed448.c'; then $(CYGPATH_W) 'suites/test_ed448.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_ed448.c'; fi`
+
 suites/libstrongswan_tests-test_signature_params.o: suites/test_signature_params.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libstrongswan_tests_CFLAGS) $(CFLAGS) -MT suites/libstrongswan_tests-test_signature_params.o -MD -MP -MF suites/$(DEPDIR)/libstrongswan_tests-test_signature_params.Tpo -c -o suites/libstrongswan_tests-test_signature_params.o `test -f 'suites/test_signature_params.c' || echo '$(srcdir)/'`suites/test_signature_params.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libstrongswan_tests-test_signature_params.Tpo suites/$(DEPDIR)/libstrongswan_tests-test_signature_params.Po
diff --git a/src/libstrongswan/tests/suites/test_ed25519.c b/src/libstrongswan/tests/suites/test_ed25519.c
index 86cbb1bc0..c52b90885 100644
--- a/src/libstrongswan/tests/suites/test_ed25519.c
+++ b/src/libstrongswan/tests/suites/test_ed25519.c
@@ -24,10 +24,12 @@ struct sig_test_t {
 	chunk_t pubkey;
 	chunk_t msg;
 	chunk_t sig;
+	chunk_t fp_pk;
+	chunk_t fp_spki;
 };
 
 /**
- * Ed25519 Test Vectors from draft-irtf-cfrg-eddsa
+ * Ed25519 Test Vectors from RFC 8032
  */
 static sig_test_t sig_tests[] = {
 	/* Test 1 */
@@ -51,7 +53,13 @@ static sig_test_t sig_tests[] = {
 		0x01, 0x55, 0x5f, 0xb8, 0x82, 0x15, 0x90, 0xa3, 0x3b, 0xac,
 		0xc6, 0x1e, 0x39, 0x70, 0x1c, 0xf9, 0xb4, 0x6b, 0xd2, 0x5b,
 		0xf5, 0xf0, 0x59, 0x5b, 0xbe, 0x24, 0x65, 0x51, 0x41, 0x43,
-		0x8e, 0x7a, 0x10, 0x0b)
+		0x8e, 0x7a, 0x10, 0x0b),
+	  chunk_from_chars(
+		0x5b, 0x27, 0xaa, 0x55, 0x89, 0x17, 0x97, 0x70, 0xe4, 0x75,
+		0x75, 0xb1, 0x62, 0xa1, 0xde, 0xd9, 0x7b, 0x8b, 0xfc, 0x6d),
+	  chunk_from_chars(
+		0xa5, 0x66, 0xbe, 0x19, 0x84, 0x01, 0x73, 0x41, 0x3a, 0x61,
+		0x04, 0x83, 0x50, 0xef, 0xf2, 0x3e, 0x8f, 0xe2, 0x22, 0x66),
 	},
 	/* Test 2 */
 	{ chunk_from_chars(
@@ -75,7 +83,13 @@ static sig_test_t sig_tests[] = {
 		0x69, 0xda, 0x08, 0x5a, 0xc1, 0xe4, 0x3e, 0x15, 0x99, 0x6e,
 		0x45, 0x8f, 0x36, 0x13, 0xd0, 0xf1, 0x1d, 0x8c, 0x38, 0x7b,
 		0x2e, 0xae, 0xb4, 0x30, 0x2a, 0xee, 0xb0, 0x0d, 0x29, 0x16,
-		0x12, 0xbb, 0x0c, 0x00)
+		0x12, 0xbb, 0x0c, 0x00),
+	  chunk_from_chars(
+		0x13, 0xf7, 0x72, 0x66, 0x9e, 0x15, 0x2a, 0xe6, 0xa6, 0x2a,
+		0x60, 0xa3, 0x48, 0x8a, 0x6f, 0x29, 0x7d, 0x06, 0x13, 0xdd),
+	  chunk_from_chars(
+		0xbd, 0xae, 0x41, 0xeb, 0x5d, 0xbf, 0x88, 0xb9, 0xdf, 0x18,
+		0xda, 0xbb, 0x2d, 0xee, 0xa9, 0x1a, 0x4e, 0x03, 0x38, 0xe4),
 	},
 	/* Test 3 */
 	{ chunk_from_chars(
@@ -99,7 +113,13 @@ static sig_test_t sig_tests[] = {
 		0xc3, 0xac, 0x18, 0xff, 0x9b, 0x53, 0x8d, 0x16, 0xf2, 0x90,
 		0xae, 0x67, 0xf7, 0x60, 0x98, 0x4d, 0xc6, 0x59, 0x4a, 0x7c,
 		0x15, 0xe9, 0x71, 0x6e, 0xd2, 0x8d, 0xc0, 0x27, 0xbe, 0xce,
-		0xea, 0x1e, 0xc4, 0x0a)
+		0xea, 0x1e, 0xc4, 0x0a),
+	  chunk_from_chars(
+		0x88, 0xc7, 0x64, 0xc8, 0xbe, 0x44, 0x37, 0x4a, 0x7d, 0x2f,
+		0x5d, 0x84, 0x72, 0x1f, 0x8e, 0x32, 0x5e, 0x5b, 0xd6, 0x4c),
+	  chunk_from_chars(
+		0xad, 0x01, 0x30, 0xb1, 0x2b, 0x48, 0x62, 0x9b, 0xb9, 0xad,
+		0xea, 0x92, 0x1f, 0xfe, 0xd2, 0x9a, 0x42, 0xf0, 0xad, 0xe6),
 	},
 	/* Test 1024 */
 	{ chunk_from_chars(
@@ -235,7 +255,13 @@ static sig_test_t sig_tests[] = {
 		0xc3, 0x50, 0xaa, 0x53, 0x71, 0xb1, 0x50, 0x8f, 0x9f, 0x45,
 		0x28, 0xec, 0xea, 0x23, 0xc4, 0x36, 0xd9, 0x4b, 0x5e, 0x8f,
 		0xcd, 0x4f, 0x68, 0x1e, 0x30, 0xa6, 0xac, 0x00, 0xa9, 0x70,
-		0x4a, 0x18, 0x8a, 0x03)
+		0x4a, 0x18, 0x8a, 0x03),
+	  chunk_from_chars(
+		0x11, 0x2d, 0xb3, 0x08, 0x97, 0x6e, 0x38, 0x8f, 0x5f, 0x5e,
+		0xb0, 0xae, 0x8f, 0x5f, 0x59, 0x1d, 0xff, 0x74, 0xf4, 0x44),
+	  chunk_from_chars(
+		0xcb, 0x36, 0xcc, 0x6a, 0x82, 0x2c, 0x49, 0x40, 0xfb, 0x08,
+		0x04, 0xf6, 0x3a, 0x4f, 0x20, 0x2b, 0xe5, 0x73, 0x43, 0x2f),
 	},
 	/* Test SHA(abc) */
 	{ chunk_from_chars(
@@ -265,7 +291,13 @@ static sig_test_t sig_tests[] = {
 		0xb5, 0x89, 0x09, 0x35, 0x1f, 0xc9, 0xac, 0x90, 0xb3, 0xec,
 		0xfd, 0xfb, 0xc7, 0xc6, 0x64, 0x31, 0xe0, 0x30, 0x3d, 0xca,
 		0x17, 0x9c, 0x13, 0x8a, 0xc1, 0x7a, 0xd9, 0xbe, 0xf1, 0x17,
-		0x73, 0x31, 0xa7, 0x04)
+		0x73, 0x31, 0xa7, 0x04),
+	  chunk_from_chars(
+		0x26, 0x4c, 0xa5, 0x7f, 0x89, 0x6d, 0x64, 0x81, 0xd1, 0x87,
+		0xe9, 0x89, 0x47, 0x29, 0x5a, 0xfe, 0xe3, 0x6d, 0x82, 0x44),
+	  chunk_from_chars(
+		0x27, 0x88, 0xfc, 0x14, 0xb1, 0xcd, 0xd0, 0x24, 0xd5, 0x9d,
+		0x31, 0x65, 0x59, 0x63, 0x69, 0xcf, 0xaf, 0x50, 0x10, 0xe7),
 	}
 };
 
@@ -273,24 +305,34 @@ START_TEST(test_ed25519_sign)
 {
 	private_key_t *key;
 	public_key_t *pubkey, *public;
-	chunk_t sig, encoding;
+	chunk_t sig, encoding, fp;
 
 	/* load private key */
 	key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED25519,
 					BUILD_BLOB_ASN1_DER, sig_tests[_i].key, BUILD_END);
 	ck_assert(key != NULL);
 	ck_assert(key->get_encoding(key, PRIVKEY_ASN1_DER, &encoding));
-	ck_assert(chunk_equals(encoding, sig_tests[_i].key));
+	ck_assert_chunk_eq(encoding, sig_tests[_i].key);
 	chunk_free(&encoding);
 
+	ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp);
+	ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp);
+
 	/* load public key */
 	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519,
 					BUILD_BLOB_ASN1_DER, sig_tests[_i].pubkey, BUILD_END);
 	ck_assert(pubkey != NULL);
 	ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding));
-	ck_assert(chunk_equals(encoding, sig_tests[_i].pubkey));
+	ck_assert_chunk_eq(encoding, sig_tests[_i].pubkey);
 	chunk_free(&encoding);
 
+	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp);
+	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp);
+
 	/* compare public keys */
 	public = key->get_public_key(key);
 	ck_assert(public != NULL);
@@ -299,7 +341,7 @@ START_TEST(test_ed25519_sign)
 	/* sign */
 	ck_assert(key->sign(key, SIGN_ED25519, NULL, sig_tests[_i].msg, &sig));
 	ck_assert(sig.len == 64);
-	ck_assert(chunk_equals(sig, sig_tests[_i].sig));
+	ck_assert_chunk_eq(sig, sig_tests[_i].sig);
 
 	/* verify */
 	ck_assert(pubkey->verify(pubkey, SIGN_ED25519, NULL, sig_tests[_i].msg,
@@ -364,7 +406,7 @@ START_TEST(test_ed25519_gen)
 	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub));
 	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub));
 	ck_assert(fp_pub.ptr != NULL);
-	ck_assert(chunk_equals(fp_pub, fp_priv));
+	ck_assert_chunk_eq(fp_pub, fp_priv);
 
 	/* clone public key */
 	pubkey2 = pubkey->get_ref(pubkey);
@@ -429,6 +471,16 @@ static chunk_t zero_pk = chunk_from_chars(
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00);
 
+/* sig_tests[0].sig with s+L */
+static chunk_t malleable_sig = chunk_from_chars(
+	0xe5, 0x56, 0x43, 0x00, 0xc3, 0x60, 0xac, 0x72, 0x90, 0x86,
+	0xe2, 0xcc, 0x80, 0x6e, 0x82, 0x8a, 0x84, 0x87, 0x7f, 0x1e,
+	0xb8, 0xe5, 0xd9, 0x74, 0xd8, 0x73, 0xe0, 0x65, 0x22, 0x49,
+	0x01, 0x55, 0x4c, 0x8c, 0x78, 0x72, 0xaa, 0x06, 0x4e, 0x04,
+	0x9d, 0xbb, 0x30, 0x13, 0xfb, 0xf2, 0x93, 0x80, 0xd2, 0x5b,
+	0xf5, 0xf0, 0x59, 0x5b, 0xbe, 0x24, 0x65, 0x51, 0x41, 0x43,
+	0x8e, 0x7a, 0x10, 0x1b);
+
 START_TEST(test_ed25519_fail)
 {
 	private_key_t *key;
@@ -479,6 +531,16 @@ START_TEST(test_ed25519_fail)
 	ck_assert(!pubkey->verify(pubkey, SIGN_ED25519, NULL, chunk_empty,
 							  chunk_empty));
 
+	/* RFC 8032, section 5.1.7 requires that 0 <= s < L to prevent signature
+	 * malleability.  Only a warning because Botan and OpenSSL are both
+	 * vulnerable to this. */
+	if (pubkey->verify(pubkey, SIGN_ED25519, NULL, sig_tests[0].msg,
+					   malleable_sig))
+	{
+		warn("Ed25519 signature verification is vulnerable to malleable "
+			 "signatures");
+	}
+
 	/* malformed signature */
 	sig = chunk_create(sig1, 64);
 	memcpy(sig1, sig_tests[0].sig.ptr, 64);
diff --git a/src/libstrongswan/tests/suites/test_ed448.c b/src/libstrongswan/tests/suites/test_ed448.c
new file mode 100644
index 000000000..288da19a0
--- /dev/null
+++ b/src/libstrongswan/tests/suites/test_ed448.c
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 "test_suite.h"
+
+#include <time.h>
+
+typedef struct sig_test_t sig_test_t;
+
+struct sig_test_t {
+	chunk_t key;
+	chunk_t pubkey;
+	chunk_t msg;
+	chunk_t sig;
+	chunk_t fp_pk;
+	chunk_t fp_spki;
+};
+
+/**
+ * Ed448 Test Vectors from RFC 8032
+ */
+static sig_test_t sig_tests[] = {
+	/* Blank */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0x6c,0x82,0xa5,0x62,0xcb,0x80,0x8d,0x10,0xd6,0x32,0xbe,0x89,0xc8,0x51,0x3e,0xbf,
+		0x6c,0x92,0x9f,0x34,0xdd,0xfa,0x8c,0x9f,0x63,0xc9,0x96,0x0e,0xf6,0xe3,0x48,0xa3,
+		0x52,0x8c,0x8a,0x3f,0xcc,0x2f,0x04,0x4e,0x39,0xa3,0xfc,0x5b,0x94,0x49,0x2f,0x8f,
+		0x03,0x2e,0x75,0x49,0xa2,0x00,0x98,0xf9,0x5b),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x5f,0xd7,0x44,0x9b,
+		0x59,0xb4,0x61,0xfd,0x2c,0xe7,0x87,0xec,0x61,0x6a,0xd4,0x6a,0x1d,0xa1,0x34,0x24,
+		0x85,0xa7,0x0e,0x1f,0x8a,0x0e,0xa7,0x5d,0x80,0xe9,0x67,0x78,0xed,0xf1,0x24,0x76,
+		0x9b,0x46,0xc7,0x06,0x1b,0xd6,0x78,0x3d,0xf1,0xe5,0x0f,0x6c,0xd1,0xfa,0x1a,0xbe,
+		0xaf,0xe8,0x25,0x61,0x80),
+	  { NULL, 0 },
+	  chunk_from_chars(
+		0x53,0x3a,0x37,0xf6,0xbb,0xe4,0x57,0x25,0x1f,0x02,0x3c,0x0d,0x88,0xf9,0x76,0xae,
+		0x2d,0xfb,0x50,0x4a,0x84,0x3e,0x34,0xd2,0x07,0x4f,0xd8,0x23,0xd4,0x1a,0x59,0x1f,
+		0x2b,0x23,0x3f,0x03,0x4f,0x62,0x82,0x81,0xf2,0xfd,0x7a,0x22,0xdd,0xd4,0x7d,0x78,
+		0x28,0xc5,0x9b,0xd0,0xa2,0x1b,0xfd,0x39,0x80,0xff,0x0d,0x20,0x28,0xd4,0xb1,0x8a,
+		0x9d,0xf6,0x3e,0x00,0x6c,0x5d,0x1c,0x2d,0x34,0x5b,0x92,0x5d,0x8d,0xc0,0x0b,0x41,
+		0x04,0x85,0x2d,0xb9,0x9a,0xc5,0xc7,0xcd,0xda,0x85,0x30,0xa1,0x13,0xa0,0xf4,0xdb,
+		0xb6,0x11,0x49,0xf0,0x5a,0x73,0x63,0x26,0x8c,0x71,0xd9,0x58,0x08,0xff,0x2e,0x65,
+		0x26,0x00),
+	  chunk_from_chars(
+		0x6d,0xe0,0x8a,0x72,0x35,0x1e,0xf1,0xad,0xeb,0xca,0x2c,0xd7,0xf1,0xfd,0xa6,0x91,
+		0x54,0xad,0xfa,0x4f),
+	  chunk_from_chars(
+		0x1b,0x7a,0x47,0x56,0x91,0xb8,0x41,0x33,0x0d,0x2e,0x4d,0xa5,0xe6,0x13,0xb9,0x89,
+		0xda,0xce,0xc5,0x8e),
+	},
+	/* 1 octet */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0xc4,0xea,0xb0,0x5d,0x35,0x70,0x07,0xc6,0x32,0xf3,0xdb,0xb4,0x84,0x89,0x92,0x4d,
+		0x55,0x2b,0x08,0xfe,0x0c,0x35,0x3a,0x0d,0x4a,0x1f,0x00,0xac,0xda,0x2c,0x46,0x3a,
+		0xfb,0xea,0x67,0xc5,0xe8,0xd2,0x87,0x7c,0x5e,0x3b,0xc3,0x97,0xa6,0x59,0x94,0x9e,
+		0xf8,0x02,0x1e,0x95,0x4e,0x0a,0x12,0x27,0x4e),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x43,0xba,0x28,0xf4,
+		0x30,0xcd,0xff,0x45,0x6a,0xe5,0x31,0x54,0x5f,0x7e,0xcd,0x0a,0xc8,0x34,0xa5,0x5d,
+		0x93,0x58,0xc0,0x37,0x2b,0xfa,0x0c,0x6c,0x67,0x98,0xc0,0x86,0x6a,0xea,0x01,0xeb,
+		0x00,0x74,0x28,0x02,0xb8,0x43,0x8e,0xa4,0xcb,0x82,0x16,0x9c,0x23,0x51,0x60,0x62,
+		0x7b,0x4c,0x3a,0x94,0x80),
+	  chunk_from_chars(
+		0x03),
+	  chunk_from_chars(
+		0x26,0xb8,0xf9,0x17,0x27,0xbd,0x62,0x89,0x7a,0xf1,0x5e,0x41,0xeb,0x43,0xc3,0x77,
+		0xef,0xb9,0xc6,0x10,0xd4,0x8f,0x23,0x35,0xcb,0x0b,0xd0,0x08,0x78,0x10,0xf4,0x35,
+		0x25,0x41,0xb1,0x43,0xc4,0xb9,0x81,0xb7,0xe1,0x8f,0x62,0xde,0x8c,0xcd,0xf6,0x33,
+		0xfc,0x1b,0xf0,0x37,0xab,0x7c,0xd7,0x79,0x80,0x5e,0x0d,0xbc,0xc0,0xaa,0xe1,0xcb,
+		0xce,0xe1,0xaf,0xb2,0xe0,0x27,0xdf,0x36,0xbc,0x04,0xdc,0xec,0xbf,0x15,0x43,0x36,
+		0xc1,0x9f,0x0a,0xf7,0xe0,0xa6,0x47,0x29,0x05,0xe7,0x99,0xf1,0x95,0x3d,0x2a,0x0f,
+		0xf3,0x34,0x8a,0xb2,0x1a,0xa4,0xad,0xaf,0xd1,0xd2,0x34,0x44,0x1c,0xf8,0x07,0xc0,
+		0x3a,0x00),
+	  chunk_from_chars(
+		0x74,0xa7,0x4b,0x23,0x69,0x98,0x17,0x46,0x1f,0xca,0xcf,0x84,0xf7,0xc6,0x3e,0x05,
+		0x2a,0x1b,0xf9,0xb8),
+	  chunk_from_chars(
+		0xf6,0x76,0xf7,0x63,0x82,0x2b,0x53,0x5c,0x61,0x9c,0xfa,0x4a,0x59,0x7d,0xdd,0xae,
+		0x13,0x34,0xf0,0xb1),
+	},
+	/* 11 octets */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0xcd,0x23,0xd2,0x4f,0x71,0x42,0x74,0xe7,0x44,0x34,0x32,0x37,0xb9,0x32,0x90,0xf5,
+		0x11,0xf6,0x42,0x5f,0x98,0xe6,0x44,0x59,0xff,0x20,0x3e,0x89,0x85,0x08,0x3f,0xfd,
+		0xf6,0x05,0x00,0x55,0x3a,0xbc,0x0e,0x05,0xcd,0x02,0x18,0x4b,0xdb,0x89,0xc4,0xcc,
+		0xd6,0x7e,0x18,0x79,0x51,0x26,0x7e,0xb3,0x28),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xdc,0xea,0x9e,0x78,
+		0xf3,0x5a,0x1b,0xf3,0x49,0x9a,0x83,0x1b,0x10,0xb8,0x6c,0x90,0xaa,0xc0,0x1c,0xd8,
+		0x4b,0x67,0xa0,0x10,0x9b,0x55,0xa3,0x6e,0x93,0x28,0xb1,0xe3,0x65,0xfc,0xe1,0x61,
+		0xd7,0x1c,0xe7,0x13,0x1a,0x54,0x3e,0xa4,0xcb,0x5f,0x7e,0x9f,0x1d,0x8b,0x00,0x69,
+		0x64,0x47,0x00,0x14,0x00),
+	  chunk_from_chars(
+		0x0c,0x3e,0x54,0x40,0x74,0xec,0x63,0xb0,0x26,0x5e,0x0c),
+	  chunk_from_chars(
+		0x1f,0x0a,0x88,0x88,0xce,0x25,0xe8,0xd4,0x58,0xa2,0x11,0x30,0x87,0x9b,0x84,0x0a,
+		0x90,0x89,0xd9,0x99,0xaa,0xba,0x03,0x9e,0xaf,0x3e,0x3a,0xfa,0x09,0x0a,0x09,0xd3,
+		0x89,0xdb,0xa8,0x2c,0x4f,0xf2,0xae,0x8a,0xc5,0xcd,0xfb,0x7c,0x55,0xe9,0x4d,0x5d,
+		0x96,0x1a,0x29,0xfe,0x01,0x09,0x94,0x1e,0x00,0xb8,0xdb,0xde,0xea,0x6d,0x3b,0x05,
+		0x10,0x68,0xdf,0x72,0x54,0xc0,0xcd,0xc1,0x29,0xcb,0xe6,0x2d,0xb2,0xdc,0x95,0x7d,
+		0xbb,0x47,0xb5,0x1f,0xd3,0xf2,0x13,0xfb,0x86,0x98,0xf0,0x64,0x77,0x42,0x50,0xa5,
+		0x02,0x89,0x61,0xc9,0xbf,0x8f,0xfd,0x97,0x3f,0xe5,0xd5,0xc2,0x06,0x49,0x2b,0x14,
+		0x0e,0x00),
+	  chunk_from_chars(
+		0x3b,0x56,0x55,0xa4,0xce,0x4c,0xec,0x67,0x77,0x9c,0x9f,0xeb,0xfe,0x6f,0x38,0xba,
+		0x88,0xc2,0x25,0x10),
+	  chunk_from_chars(
+		0x71,0xcb,0xf2,0xb7,0x1b,0x3b,0x77,0xcb,0xd6,0x41,0x05,0x02,0x72,0x31,0xa6,0x91,
+		0x27,0x3f,0xe5,0x51),
+	},
+	/* 12 octets */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0x25,0x8c,0xdd,0x4a,0xda,0x32,0xed,0x9c,0x9f,0xf5,0x4e,0x63,0x75,0x6a,0xe5,0x82,
+		0xfb,0x8f,0xab,0x2a,0xc7,0x21,0xf2,0xc8,0xe6,0x76,0xa7,0x27,0x68,0x51,0x3d,0x93,
+		0x9f,0x63,0xdd,0xdb,0x55,0x60,0x91,0x33,0xf2,0x9a,0xdf,0x86,0xec,0x99,0x29,0xdc,
+		0xcb,0x52,0xc1,0xc5,0xfd,0x2f,0xf7,0xe2,0x1b),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x3b,0xa1,0x6d,0xa0,
+		0xc6,0xf2,0xcc,0x1f,0x30,0x18,0x77,0x40,0x75,0x6f,0x5e,0x79,0x8d,0x6b,0xc5,0xfc,
+		0x01,0x5d,0x7c,0x63,0xcc,0x95,0x10,0xee,0x3f,0xd4,0x4a,0xdc,0x24,0xd8,0xe9,0x68,
+		0xb6,0xe4,0x6e,0x6f,0x94,0xd1,0x9b,0x94,0x53,0x61,0x72,0x6b,0xd7,0x5e,0x14,0x9e,
+		0xf0,0x98,0x17,0xf5,0x80),
+	  chunk_from_chars(
+		0x64,0xa6,0x5f,0x3c,0xde,0xdc,0xdd,0x66,0x81,0x1e,0x29,0x15),
+	  chunk_from_chars(
+		0x7e,0xee,0xab,0x7c,0x4e,0x50,0xfb,0x79,0x9b,0x41,0x8e,0xe5,0xe3,0x19,0x7f,0xf6,
+		0xbf,0x15,0xd4,0x3a,0x14,0xc3,0x43,0x89,0xb5,0x9d,0xd1,0xa7,0xb1,0xb8,0x5b,0x4a,
+		0xe9,0x04,0x38,0xac,0xa6,0x34,0xbe,0xa4,0x5e,0x3a,0x26,0x95,0xf1,0x27,0x0f,0x07,
+		0xfd,0xcd,0xf7,0xc6,0x2b,0x8e,0xfe,0xaf,0x00,0xb4,0x5c,0x2c,0x96,0xba,0x45,0x7e,
+		0xb1,0xa8,0xbf,0x07,0x5a,0x3d,0xb2,0x8e,0x5c,0x24,0xf6,0xb9,0x23,0xed,0x4a,0xd7,
+		0x47,0xc3,0xc9,0xe0,0x3c,0x70,0x79,0xef,0xb8,0x7c,0xb1,0x10,0xd3,0xa9,0x98,0x61,
+		0xe7,0x20,0x03,0xcb,0xae,0x6d,0x6b,0x8b,0x82,0x7e,0x4e,0x6c,0x14,0x30,0x64,0xff,
+		0x3c,0x00),
+	  chunk_from_chars(
+		0x56,0x8e,0xad,0x67,0xa7,0x83,0x78,0xfe,0x8f,0xaf,0xa7,0x87,0x2e,0xc8,0x95,0xa0,
+		0xde,0x05,0x37,0x4c),
+	  chunk_from_chars(
+		0xed,0x1b,0xe5,0xa1,0x97,0x23,0x59,0x4d,0x86,0x6b,0x6b,0xef,0xfb,0x81,0xe4,0x8e,
+		0xf7,0x42,0xe0,0x81),
+	},
+	/* 13 octets */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0x7e,0xf4,0xe8,0x45,0x44,0x23,0x67,0x52,0xfb,0xb5,0x6b,0x8f,0x31,0xa2,0x3a,0x10,
+		0xe4,0x28,0x14,0xf5,0xf5,0x5c,0xa0,0x37,0xcd,0xcc,0x11,0xc6,0x4c,0x9a,0x3b,0x29,
+		0x49,0xc1,0xbb,0x60,0x70,0x03,0x14,0x61,0x17,0x32,0xa6,0xc2,0xfe,0xa9,0x8e,0xeb,
+		0xc0,0x26,0x6a,0x11,0xa9,0x39,0x70,0x10,0x0e),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xb3,0xda,0x07,0x9b,
+		0x0a,0xa4,0x93,0xa5,0x77,0x20,0x29,0xf0,0x46,0x7b,0xae,0xbe,0xe5,0xa8,0x11,0x2d,
+		0x9d,0x3a,0x22,0x53,0x23,0x61,0xda,0x29,0x4f,0x7b,0xb3,0x81,0x5c,0x5d,0xc5,0x9e,
+		0x17,0x6b,0x4d,0x9f,0x38,0x1c,0xa0,0x93,0x8e,0x13,0xc6,0xc0,0x7b,0x17,0x4b,0xe6,
+		0x5d,0xfa,0x57,0x8e,0x80),
+	  chunk_from_chars(
+		0x64,0xa6,0x5f,0x3c,0xde,0xdc,0xdd,0x66,0x81,0x1e,0x29,0x15,0xe7),
+	  chunk_from_chars(
+		0x6a,0x12,0x06,0x6f,0x55,0x33,0x1b,0x6c,0x22,0xac,0xd5,0xd5,0xbf,0xc5,0xd7,0x12,
+		0x28,0xfb,0xda,0x80,0xae,0x8d,0xec,0x26,0xbd,0xd3,0x06,0x74,0x3c,0x50,0x27,0xcb,
+		0x48,0x90,0x81,0x0c,0x16,0x2c,0x02,0x74,0x68,0x67,0x5e,0xcf,0x64,0x5a,0x83,0x17,
+		0x6c,0x0d,0x73,0x23,0xa2,0xcc,0xde,0x2d,0x80,0xef,0xe5,0xa1,0x26,0x8e,0x8a,0xca,
+		0x1d,0x6f,0xbc,0x19,0x4d,0x3f,0x77,0xc4,0x49,0x86,0xeb,0x4a,0xb4,0x17,0x79,0x19,
+		0xad,0x8b,0xec,0x33,0xeb,0x47,0xbb,0xb5,0xfc,0x6e,0x28,0x19,0x6f,0xd1,0xca,0xf5,
+		0x6b,0x4e,0x7e,0x0b,0xa5,0x51,0x92,0x34,0xd0,0x47,0x15,0x5a,0xc7,0x27,0xa1,0x05,
+		0x31,0x00),
+	  chunk_from_chars(
+		0x6e,0xb1,0xb6,0x33,0x76,0xa8,0x0f,0x84,0x26,0x23,0xfb,0xaa,0x9e,0xaa,0x1d,0x8d,
+		0x6d,0xa5,0x75,0x4e),
+	  chunk_from_chars(
+		0xfa,0x2f,0xeb,0xff,0x13,0xc0,0xee,0xd0,0x3b,0xc6,0xf2,0x7d,0xb8,0x61,0xe5,0x9d,
+		0x16,0x53,0xb1,0x11),
+	},
+	/* 64 octets */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0xd6,0x5d,0xf3,0x41,0xad,0x13,0xe0,0x08,0x56,0x76,0x88,0xba,0xed,0xda,0x8e,0x9d,
+		0xcd,0xc1,0x7d,0xc0,0x24,0x97,0x4e,0xa5,0xb4,0x22,0x7b,0x65,0x30,0xe3,0x39,0xbf,
+		0xf2,0x1f,0x99,0xe6,0x8c,0xa6,0x96,0x8f,0x3c,0xca,0x6d,0xfe,0x0f,0xb9,0xf4,0xfa,
+		0xb4,0xfa,0x13,0x5d,0x55,0x42,0xea,0x3f,0x01),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xdf,0x97,0x05,0xf5,
+		0x8e,0xdb,0xab,0x80,0x2c,0x7f,0x83,0x63,0xcf,0xe5,0x56,0x0a,0xb1,0xc6,0x13,0x2c,
+		0x20,0xa9,0xf1,0xdd,0x16,0x34,0x83,0xa2,0x6f,0x8a,0xc5,0x3a,0x39,0xd6,0x80,0x8b,
+		0xf4,0xa1,0xdf,0xbd,0x26,0x1b,0x09,0x9b,0xb0,0x3b,0x3f,0xb5,0x09,0x06,0xcb,0x28,
+		0xbd,0x8a,0x08,0x1f,0x00),
+	  chunk_from_chars(
+		0xbd,0x0f,0x6a,0x37,0x47,0xcd,0x56,0x1b,0xdd,0xdf,0x46,0x40,0xa3,0x32,0x46,0x1a,
+		0x4a,0x30,0xa1,0x2a,0x43,0x4c,0xd0,0xbf,0x40,0xd7,0x66,0xd9,0xc6,0xd4,0x58,0xe5,
+		0x51,0x22,0x04,0xa3,0x0c,0x17,0xd1,0xf5,0x0b,0x50,0x79,0x63,0x1f,0x64,0xeb,0x31,
+		0x12,0x18,0x2d,0xa3,0x00,0x58,0x35,0x46,0x11,0x13,0x71,0x8d,0x1a,0x5e,0xf9,0x44),
+	  chunk_from_chars(
+		0x55,0x4b,0xc2,0x48,0x08,0x60,0xb4,0x9e,0xab,0x85,0x32,0xd2,0xa5,0x33,0xb7,0xd5,
+		0x78,0xef,0x47,0x3e,0xeb,0x58,0xc9,0x8b,0xb2,0xd0,0xe1,0xce,0x48,0x8a,0x98,0xb1,
+		0x8d,0xfd,0xe9,0xb9,0xb9,0x07,0x75,0xe6,0x7f,0x47,0xd4,0xa1,0xc3,0x48,0x20,0x58,
+		0xef,0xc9,0xf4,0x0d,0x2c,0xa0,0x33,0xa0,0x80,0x1b,0x63,0xd4,0x5b,0x3b,0x72,0x2e,
+		0xf5,0x52,0xba,0xd3,0xb4,0xcc,0xb6,0x67,0xda,0x35,0x01,0x92,0xb6,0x1c,0x50,0x8c,
+		0xf7,0xb6,0xb5,0xad,0xad,0xc2,0xc8,0xd9,0xa4,0x46,0xef,0x00,0x3f,0xb0,0x5c,0xba,
+		0x5f,0x30,0xe8,0x8e,0x36,0xec,0x27,0x03,0xb3,0x49,0xca,0x22,0x9c,0x26,0x70,0x83,
+		0x39,0x00),
+	  chunk_from_chars(
+		0x2b,0xb0,0xd4,0x29,0xb8,0x51,0x3f,0xb5,0x9d,0x07,0xd0,0xb0,0x1f,0x4a,0x39,0x25,
+		0x33,0xae,0x3e,0x64),
+	  chunk_from_chars(
+		0x79,0xbb,0x37,0xe4,0x2a,0xf9,0x58,0xb7,0xa4,0x58,0x18,0x88,0x4b,0x82,0x8f,0xfb,
+		0x9c,0x74,0xce,0x9d),
+	},
+	/* 256 octets */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0x2e,0xc5,0xfe,0x3c,0x17,0x04,0x5a,0xbd,0xb1,0x36,0xa5,0xe6,0xa9,0x13,0xe3,0x2a,
+		0xb7,0x5a,0xe6,0x8b,0x53,0xd2,0xfc,0x14,0x9b,0x77,0xe5,0x04,0x13,0x2d,0x37,0x56,
+		0x9b,0x7e,0x76,0x6b,0xa7,0x4a,0x19,0xbd,0x61,0x62,0x34,0x3a,0x21,0xc8,0x59,0x0a,
+		0xa9,0xce,0xbc,0xa9,0x01,0x4c,0x63,0x6d,0xf5),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x79,0x75,0x6f,0x01,
+		0x4d,0xcf,0xe2,0x07,0x9f,0x5d,0xd9,0xe7,0x18,0xbe,0x41,0x71,0xe2,0xef,0x24,0x86,
+		0xa0,0x8f,0x25,0x18,0x6f,0x6b,0xff,0x43,0xa9,0x93,0x6b,0x9b,0xfe,0x12,0x40,0x2b,
+		0x08,0xae,0x65,0x79,0x8a,0x3d,0x81,0xe2,0x2e,0x9e,0xc8,0x0e,0x76,0x90,0x86,0x2e,
+		0xf3,0xd4,0xed,0x3a,0x00),
+	  chunk_from_chars(
+		0x15,0x77,0x75,0x32,0xb0,0xbd,0xd0,0xd1,0x38,0x9f,0x63,0x6c,0x5f,0x6b,0x9b,0xa7,
+		0x34,0xc9,0x0a,0xf5,0x72,0x87,0x7e,0x2d,0x27,0x2d,0xd0,0x78,0xaa,0x1e,0x56,0x7c,
+		0xfa,0x80,0xe1,0x29,0x28,0xbb,0x54,0x23,0x30,0xe8,0x40,0x9f,0x31,0x74,0x50,0x41,
+		0x07,0xec,0xd5,0xef,0xac,0x61,0xae,0x75,0x04,0xda,0xbe,0x2a,0x60,0x2e,0xde,0x89,
+		0xe5,0xcc,0xa6,0x25,0x7a,0x7c,0x77,0xe2,0x7a,0x70,0x2b,0x3a,0xe3,0x9f,0xc7,0x69,
+		0xfc,0x54,0xf2,0x39,0x5a,0xe6,0xa1,0x17,0x8c,0xab,0x47,0x38,0xe5,0x43,0x07,0x2f,
+		0xc1,0xc1,0x77,0xfe,0x71,0xe9,0x2e,0x25,0xbf,0x03,0xe4,0xec,0xb7,0x2f,0x47,0xb6,
+		0x4d,0x04,0x65,0xaa,0xea,0x4c,0x7f,0xad,0x37,0x25,0x36,0xc8,0xba,0x51,0x6a,0x60,
+		0x39,0xc3,0xc2,0xa3,0x9f,0x0e,0x4d,0x83,0x2b,0xe4,0x32,0xdf,0xa9,0xa7,0x06,0xa6,
+		0xe5,0xc7,0xe1,0x9f,0x39,0x79,0x64,0xca,0x42,0x58,0x00,0x2f,0x7c,0x05,0x41,0xb5,
+		0x90,0x31,0x6d,0xbc,0x56,0x22,0xb6,0xb2,0xa6,0xfe,0x7a,0x4a,0xbf,0xfd,0x96,0x10,
+		0x5e,0xca,0x76,0xea,0x7b,0x98,0x81,0x6a,0xf0,0x74,0x8c,0x10,0xdf,0x04,0x8c,0xe0,
+		0x12,0xd9,0x01,0x01,0x5a,0x51,0xf1,0x89,0xf3,0x88,0x81,0x45,0xc0,0x36,0x50,0xaa,
+		0x23,0xce,0x89,0x4c,0x3b,0xd8,0x89,0xe0,0x30,0xd5,0x65,0x07,0x1c,0x59,0xf4,0x09,
+		0xa9,0x98,0x1b,0x51,0x87,0x8f,0xd6,0xfc,0x11,0x06,0x24,0xdc,0xbc,0xde,0x0b,0xf7,
+		0xa6,0x9c,0xcc,0xe3,0x8f,0xab,0xdf,0x86,0xf3,0xbe,0xf6,0x04,0x48,0x19,0xde,0x11),
+	  chunk_from_chars(
+		0xc6,0x50,0xdd,0xbb,0x06,0x01,0xc1,0x9c,0xa1,0x14,0x39,0xe1,0x64,0x0d,0xd9,0x31,
+		0xf4,0x3c,0x51,0x8e,0xa5,0xbe,0xa7,0x0d,0x3d,0xcd,0xe5,0xf4,0x19,0x1f,0xe5,0x3f,
+		0x00,0xcf,0x96,0x65,0x46,0xb7,0x2b,0xcc,0x7d,0x58,0xbe,0x2b,0x9b,0xad,0xef,0x28,
+		0x74,0x39,0x54,0xe3,0xa4,0x4a,0x23,0xf8,0x80,0xe8,0xd4,0xf1,0xcf,0xce,0x2d,0x7a,
+		0x61,0x45,0x2d,0x26,0xda,0x05,0x89,0x6f,0x0a,0x50,0xda,0x66,0xa2,0x39,0xa8,0xa1,
+		0x88,0xb6,0xd8,0x25,0xb3,0x30,0x5a,0xd7,0x7b,0x73,0xfb,0xac,0x08,0x36,0xec,0xc6,
+		0x09,0x87,0xfd,0x08,0x52,0x7c,0x1a,0x8e,0x80,0xd5,0x82,0x3e,0x65,0xca,0xfe,0x2a,
+		0x3d,0x00),
+	  chunk_from_chars(
+		0xfc,0x02,0xc5,0x25,0x74,0x09,0x8f,0xbb,0xaf,0x8c,0xad,0x02,0x14,0x9d,0xef,0x0d,
+		0x94,0xb7,0x96,0x5f),
+	  chunk_from_chars(
+		0x63,0x03,0x8e,0x1f,0xcc,0x69,0x1e,0x2f,0x9d,0xb3,0x57,0x0f,0xad,0xbc,0x01,0x35,
+		0x63,0xdb,0x06,0xba),
+	},
+	/* 1023 octets */
+	{ chunk_from_chars(
+		0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39,
+		0x87,0x2d,0x09,0x37,0x80,0xf5,0xd3,0x73,0x0d,0xf7,0xc2,0x12,0x66,0x4b,0x37,0xb8,
+		0xa0,0xf2,0x4f,0x56,0x81,0x0d,0xaa,0x83,0x82,0xcd,0x4f,0xa3,0xf7,0x76,0x34,0xec,
+		0x44,0xdc,0x54,0xf1,0xc2,0xed,0x9b,0xea,0x86,0xfa,0xfb,0x76,0x32,0xd8,0xbe,0x19,
+		0x9e,0xa1,0x65,0xf5,0xad,0x55,0xdd,0x9c,0xe8),
+	  chunk_from_chars(
+		0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xa8,0x1b,0x2e,0x8a,
+		0x70,0xa5,0xac,0x94,0xff,0xdb,0xcc,0x9b,0xad,0xfc,0x3f,0xeb,0x08,0x01,0xf2,0x58,
+		0x57,0x8b,0xb1,0x14,0xad,0x44,0xec,0xe1,0xec,0x0e,0x79,0x9d,0xa0,0x8e,0xff,0xb8,
+		0x1c,0x5d,0x68,0x5c,0x0c,0x56,0xf6,0x4e,0xec,0xae,0xf8,0xcd,0xf1,0x1c,0xc3,0x87,
+		0x37,0x83,0x8c,0xf4,0x00),
+	  chunk_from_chars(
+		0x6d,0xdf,0x80,0x2e,0x1a,0xae,0x49,0x86,0x93,0x5f,0x7f,0x98,0x1b,0xa3,0xf0,0x35,
+		0x1d,0x62,0x73,0xc0,0xa0,0xc2,0x2c,0x9c,0x0e,0x83,0x39,0x16,0x8e,0x67,0x54,0x12,
+		0xa3,0xde,0xbf,0xaf,0x43,0x5e,0xd6,0x51,0x55,0x80,0x07,0xdb,0x43,0x84,0xb6,0x50,
+		0xfc,0xc0,0x7e,0x3b,0x58,0x6a,0x27,0xa4,0xf7,0xa0,0x0a,0xc8,0xa6,0xfe,0xc2,0xcd,
+		0x86,0xae,0x4b,0xf1,0x57,0x0c,0x41,0xe6,0xa4,0x0c,0x93,0x1d,0xb2,0x7b,0x2f,0xaa,
+		0x15,0xa8,0xce,0xdd,0x52,0xcf,0xf7,0x36,0x2c,0x4e,0x6e,0x23,0xda,0xec,0x0f,0xbc,
+		0x3a,0x79,0xb6,0x80,0x6e,0x31,0x6e,0xfc,0xc7,0xb6,0x81,0x19,0xbf,0x46,0xbc,0x76,
+		0xa2,0x60,0x67,0xa5,0x3f,0x29,0x6d,0xaf,0xdb,0xdc,0x11,0xc7,0x7f,0x77,0x77,0xe9,
+		0x72,0x66,0x0c,0xf4,0xb6,0xa9,0xb3,0x69,0xa6,0x66,0x5f,0x02,0xe0,0xcc,0x9b,0x6e,
+		0xdf,0xad,0x13,0x6b,0x4f,0xab,0xe7,0x23,0xd2,0x81,0x3d,0xb3,0x13,0x6c,0xfd,0xe9,
+		0xb6,0xd0,0x44,0x32,0x2f,0xee,0x29,0x47,0x95,0x2e,0x03,0x1b,0x73,0xab,0x5c,0x60,
+		0x33,0x49,0xb3,0x07,0xbd,0xc2,0x7b,0xc6,0xcb,0x8b,0x8b,0xbd,0x7b,0xd3,0x23,0x21,
+		0x9b,0x80,0x33,0xa5,0x81,0xb5,0x9e,0xad,0xeb,0xb0,0x9b,0x3c,0x4f,0x3d,0x22,0x77,
+		0xd4,0xf0,0x34,0x36,0x24,0xac,0xc8,0x17,0x80,0x47,0x28,0xb2,0x5a,0xb7,0x97,0x17,
+		0x2b,0x4c,0x5c,0x21,0xa2,0x2f,0x9c,0x78,0x39,0xd6,0x43,0x00,0x23,0x2e,0xb6,0x6e,
+		0x53,0xf3,0x1c,0x72,0x3f,0xa3,0x7f,0xe3,0x87,0xc7,0xd3,0xe5,0x0b,0xdf,0x98,0x13,
+		0xa3,0x0e,0x5b,0xb1,0x2c,0xf4,0xcd,0x93,0x0c,0x40,0xcf,0xb4,0xe1,0xfc,0x62,0x25,
+		0x92,0xa4,0x95,0x88,0x79,0x44,0x94,0xd5,0x6d,0x24,0xea,0x4b,0x40,0xc8,0x9f,0xc0,
+		0x59,0x6c,0xc9,0xeb,0xb9,0x61,0xc8,0xcb,0x10,0xad,0xde,0x97,0x6a,0x5d,0x60,0x2b,
+		0x1c,0x3f,0x85,0xb9,0xb9,0xa0,0x01,0xed,0x3c,0x6a,0x4d,0x3b,0x14,0x37,0xf5,0x20,
+		0x96,0xcd,0x19,0x56,0xd0,0x42,0xa5,0x97,0xd5,0x61,0xa5,0x96,0xec,0xd3,0xd1,0x73,
+		0x5a,0x8d,0x57,0x0e,0xa0,0xec,0x27,0x22,0x5a,0x2c,0x4a,0xaf,0xf2,0x63,0x06,0xd1,
+		0x52,0x6c,0x1a,0xf3,0xca,0x6d,0x9c,0xf5,0xa2,0xc9,0x8f,0x47,0xe1,0xc4,0x6d,0xb9,
+		0xa3,0x32,0x34,0xcf,0xd4,0xd8,0x1f,0x2c,0x98,0x53,0x8a,0x09,0xeb,0xe7,0x69,0x98,
+		0xd0,0xd8,0xfd,0x25,0x99,0x7c,0x7d,0x25,0x5c,0x6d,0x66,0xec,0xe6,0xfa,0x56,0xf1,
+		0x11,0x44,0x95,0x0f,0x02,0x77,0x95,0xe6,0x53,0x00,0x8f,0x4b,0xd7,0xca,0x2d,0xee,
+		0x85,0xd8,0xe9,0x0f,0x3d,0xc3,0x15,0x13,0x0c,0xe2,0xa0,0x03,0x75,0xa3,0x18,0xc7,
+		0xc3,0xd9,0x7b,0xe2,0xc8,0xce,0x5b,0x6d,0xb4,0x1a,0x62,0x54,0xff,0x26,0x4f,0xa6,
+		0x15,0x5b,0xae,0xe3,0xb0,0x77,0x3c,0x0f,0x49,0x7c,0x57,0x3f,0x19,0xbb,0x4f,0x42,
+		0x40,0x28,0x1f,0x0b,0x1f,0x4f,0x7b,0xe8,0x57,0xa4,0xe5,0x9d,0x41,0x6c,0x06,0xb4,
+		0xc5,0x0f,0xa0,0x9e,0x18,0x10,0xdd,0xc6,0xb1,0x46,0x7b,0xae,0xac,0x5a,0x36,0x68,
+		0xd1,0x1b,0x6e,0xca,0xa9,0x01,0x44,0x00,0x16,0xf3,0x89,0xf8,0x0a,0xcc,0x4d,0xb9,
+		0x77,0x02,0x5e,0x7f,0x59,0x24,0x38,0x8c,0x7e,0x34,0x0a,0x73,0x2e,0x55,0x44,0x40,
+		0xe7,0x65,0x70,0xf8,0xdd,0x71,0xb7,0xd6,0x40,0xb3,0x45,0x0d,0x1f,0xd5,0xf0,0x41,
+		0x0a,0x18,0xf9,0xa3,0x49,0x4f,0x70,0x7c,0x71,0x7b,0x79,0xb4,0xbf,0x75,0xc9,0x84,
+		0x00,0xb0,0x96,0xb2,0x16,0x53,0xb5,0xd2,0x17,0xcf,0x35,0x65,0xc9,0x59,0x74,0x56,
+		0xf7,0x07,0x03,0x49,0x7a,0x07,0x87,0x63,0x82,0x9b,0xc0,0x1b,0xb1,0xcb,0xc8,0xfa,
+		0x04,0xea,0xdc,0x9a,0x6e,0x3f,0x66,0x99,0x58,0x7a,0x9e,0x75,0xc9,0x4e,0x5b,0xab,
+		0x00,0x36,0xe0,0xb2,0xe7,0x11,0x39,0x2c,0xff,0x00,0x47,0xd0,0xd6,0xb0,0x5b,0xd2,
+		0xa5,0x88,0xbc,0x10,0x97,0x18,0x95,0x42,0x59,0xf1,0xd8,0x66,0x78,0xa5,0x79,0xa3,
+		0x12,0x0f,0x19,0xcf,0xb2,0x96,0x3f,0x17,0x7a,0xeb,0x70,0xf2,0xd4,0x84,0x48,0x26,
+		0x26,0x2e,0x51,0xb8,0x02,0x71,0x27,0x20,0x68,0xef,0x5b,0x38,0x56,0xfa,0x85,0x35,
+		0xaa,0x2a,0x88,0xb2,0xd4,0x1f,0x2a,0x0e,0x2f,0xda,0x76,0x24,0xc2,0x85,0x02,0x72,
+		0xac,0x4a,0x2f,0x56,0x1f,0x8f,0x2f,0x7a,0x31,0x8b,0xfd,0x5c,0xaf,0x96,0x96,0x14,
+		0x9e,0x4a,0xc8,0x24,0xad,0x34,0x60,0x53,0x8f,0xdc,0x25,0x42,0x1b,0xee,0xc2,0xcc,
+		0x68,0x18,0x16,0x2d,0x06,0xbb,0xed,0x0c,0x40,0xa3,0x87,0x19,0x23,0x49,0xdb,0x67,
+		0xa1,0x18,0xba,0xda,0x6c,0xd5,0xab,0x01,0x40,0xee,0x27,0x32,0x04,0xf6,0x28,0xaa,
+		0xd1,0xc1,0x35,0xf7,0x70,0x27,0x9a,0x65,0x1e,0x24,0xd8,0xc1,0x4d,0x75,0xa6,0x05,
+		0x9d,0x76,0xb9,0x6a,0x6f,0xd8,0x57,0xde,0xf5,0xe0,0xb3,0x54,0xb2,0x7a,0xb9,0x37,
+		0xa5,0x81,0x5d,0x16,0xb5,0xfa,0xe4,0x07,0xff,0x18,0x22,0x2c,0x6d,0x1e,0xd2,0x63,
+		0xbe,0x68,0xc9,0x5f,0x32,0xd9,0x08,0xbd,0x89,0x5c,0xd7,0x62,0x07,0xae,0x72,0x64,
+		0x87,0x56,0x7f,0x9a,0x67,0xda,0xd7,0x9a,0xbe,0xc3,0x16,0xf6,0x83,0xb1,0x7f,0x2d,
+		0x02,0xbf,0x07,0xe0,0xac,0x8b,0x5b,0xc6,0x16,0x2c,0xf9,0x46,0x97,0xb3,0xc2,0x7c,
+		0xd1,0xfe,0xa4,0x9b,0x27,0xf2,0x3b,0xa2,0x90,0x18,0x71,0x96,0x25,0x06,0x52,0x0c,
+		0x39,0x2d,0xa8,0xb6,0xad,0x0d,0x99,0xf7,0x01,0x3f,0xbc,0x06,0xc2,0xc1,0x7a,0x56,
+		0x95,0x00,0xc8,0xa7,0x69,0x64,0x81,0xc1,0xcd,0x33,0xe9,0xb1,0x4e,0x40,0xb8,0x2e,
+		0x79,0xa5,0xf5,0xdb,0x82,0x57,0x1b,0xa9,0x7b,0xae,0x3a,0xd3,0xe0,0x47,0x95,0x15,
+		0xbb,0x0e,0x2b,0x0f,0x3b,0xfc,0xd1,0xfd,0x33,0x03,0x4e,0xfc,0x62,0x45,0xed,0xdd,
+		0x7e,0xe2,0x08,0x6d,0xda,0xe2,0x60,0x0d,0x8c,0xa7,0x3e,0x21,0x4e,0x8c,0x2b,0x0b,
+		0xdb,0x2b,0x04,0x7c,0x6a,0x46,0x4a,0x56,0x2e,0xd7,0x7b,0x73,0xd2,0xd8,0x41,0xc4,
+		0xb3,0x49,0x73,0x55,0x12,0x57,0x71,0x3b,0x75,0x36,0x32,0xef,0xba,0x34,0x81,0x69,
+		0xab,0xc9,0x0a,0x68,0xf4,0x26,0x11,0xa4,0x01,0x26,0xd7,0xcb,0x21,0xb5,0x86,0x95,
+		0x56,0x81,0x86,0xf7,0xe5,0x69,0xd2,0xff,0x0f,0x9e,0x74,0x5d,0x04,0x87,0xdd,0x2e,
+		0xb9,0x97,0xca,0xfc,0x5a,0xbf,0x9d,0xd1,0x02,0xe6,0x2f,0xf6,0x6c,0xba,0x87),
+	  chunk_from_chars(
+		0xe3,0x01,0x34,0x5a,0x41,0xa3,0x9a,0x4d,0x72,0xff,0xf8,0xdf,0x69,0xc9,0x80,0x75,
+		0xa0,0xcc,0x08,0x2b,0x80,0x2f,0xc9,0xb2,0xb6,0xbc,0x50,0x3f,0x92,0x6b,0x65,0xbd,
+		0xdf,0x7f,0x4c,0x8f,0x1c,0xb4,0x9f,0x63,0x96,0xaf,0xc8,0xa7,0x0a,0xbe,0x6d,0x8a,
+		0xef,0x0d,0xb4,0x78,0xd4,0xc6,0xb2,0x97,0x00,0x76,0xc6,0xa0,0x48,0x4f,0xe7,0x6d,
+		0x76,0xb3,0xa9,0x76,0x25,0xd7,0x9f,0x1c,0xe2,0x40,0xe7,0xc5,0x76,0x75,0x0d,0x29,
+		0x55,0x28,0x28,0x6f,0x71,0x9b,0x41,0x3d,0xe9,0xad,0xa3,0xe8,0xeb,0x78,0xed,0x57,
+		0x36,0x03,0xce,0x30,0xd8,0xbb,0x76,0x17,0x85,0xdc,0x30,0xdb,0xc3,0x20,0x86,0x9e,
+		0x1a,0x00),
+	  chunk_from_chars(
+		0x89,0x30,0xb4,0x62,0xe0,0x28,0x45,0xf1,0x37,0xc0,0x0e,0x47,0xfe,0x64,0x3d,0x07,
+		0x02,0x7b,0x66,0xec),
+	  chunk_from_chars(
+		0xc1,0x6c,0x19,0x0e,0x3e,0xe9,0x2c,0x5e,0xd0,0x35,0x19,0x93,0x77,0x2c,0xd6,0x38,
+		0xf0,0xbc,0xe1,0x62),
+	},
+};
+
+START_TEST(test_ed448_sign)
+{
+	private_key_t *key;
+	public_key_t *pubkey, *public;
+	chunk_t sig, encoding, fp;
+
+	/* load private key */
+	key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448,
+							 BUILD_BLOB_ASN1_DER, sig_tests[_i].key, BUILD_END);
+	ck_assert(key != NULL);
+	ck_assert(key->get_encoding(key, PRIVKEY_ASN1_DER, &encoding));
+	ck_assert_chunk_eq(encoding, sig_tests[_i].key);
+	chunk_free(&encoding);
+
+	ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp);
+	ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp);
+
+	/* load public key */
+	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+								BUILD_BLOB_ASN1_DER, sig_tests[_i].pubkey, BUILD_END);
+	ck_assert(pubkey != NULL);
+	ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding));
+	ck_assert_chunk_eq(encoding, sig_tests[_i].pubkey);
+	chunk_free(&encoding);
+
+	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp);
+	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp));
+	ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp);
+
+	/* compare public keys */
+	public = key->get_public_key(key);
+	ck_assert(public != NULL);
+	ck_assert(public->equals(public, pubkey));
+
+	/* sign */
+	ck_assert(key->sign(key, SIGN_ED448, NULL, sig_tests[_i].msg, &sig));
+	ck_assert_chunk_eq(sig, sig_tests[_i].sig);
+
+	/* verify */
+	ck_assert(pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[_i].msg,
+							 sig_tests[_i].sig));
+
+	/* cleanup */
+	key->destroy(key);
+	pubkey->destroy(pubkey);
+	public->destroy(public);
+	chunk_free(&sig);
+}
+END_TEST
+
+START_TEST(test_ed448_gen)
+{
+	private_key_t *key, *key2;
+	public_key_t *pubkey, *pubkey2;
+	chunk_t msg = chunk_from_str("Ed448"), sig, encoding, fp_priv, fp_pub;
+
+	/* generate private key */
+	key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448,
+							 BUILD_KEY_SIZE, 456, BUILD_END);
+	ck_assert(key != NULL);
+	ck_assert(key->get_type(key) == KEY_ED448);
+	ck_assert(key->get_keysize(key) == 456);
+	ck_assert(!key->get_encoding(key, PRIVKEY_PGP, &encoding));
+	ck_assert(key->get_encoding(key, PRIVKEY_PEM, &encoding));
+	ck_assert(encoding.ptr != NULL);
+	ck_assert(strstr(encoding.ptr, "PRIVATE KEY"));
+	chunk_free(&encoding);
+
+	/* clone private key */
+	key2 = key->get_ref(key);
+	ck_assert(key2);
+	key2->destroy(key2);
+
+	/* decryption not supported */
+	ck_assert(!key->decrypt(key, ENCRYPT_UNKNOWN, msg, NULL));
+
+	/* wrong signature scheme */
+	ck_assert(!key->sign(key, SIGN_ED25519, NULL, msg, &sig));
+
+	/* correct signature scheme*/
+	ck_assert(key->sign(key, SIGN_ED448, NULL, msg, &sig));
+
+	/* export public key */
+	pubkey = key->get_public_key(key);
+	ck_assert(pubkey != NULL);
+	ck_assert(pubkey->get_type(pubkey) == KEY_ED448);
+	ck_assert(pubkey->get_keysize(pubkey) == 456);
+	ck_assert(pubkey->get_encoding(pubkey, PUBKEY_PEM, &encoding));
+	ck_assert(encoding.ptr != NULL);
+	ck_assert(strstr(encoding.ptr, "PUBLIC KEY"));
+	chunk_free(&encoding);
+
+	/* generate and compare public and private key fingerprints */
+	ck_assert(!key->get_fingerprint(key, KEYID_PGPV4, &fp_priv));
+	ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp_priv));
+	ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp_priv));
+	ck_assert(fp_priv.ptr != NULL);
+	ck_assert(!pubkey->get_fingerprint(pubkey, KEYID_PGPV4, &fp_pub));
+	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub));
+	ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub));
+	ck_assert(fp_pub.ptr != NULL);
+	ck_assert_chunk_eq(fp_pub, fp_priv);
+
+	/* clone public key */
+	pubkey2 = pubkey->get_ref(pubkey);
+	ck_assert(pubkey2 != NULL);
+	pubkey2->destroy(pubkey2);
+
+	/* encryption not supported */
+	ck_assert(!pubkey->encrypt(pubkey, ENCRYPT_UNKNOWN, msg, NULL));
+
+	/* verify with wrong signature scheme */
+	ck_assert(!pubkey->verify(pubkey, SIGN_ED25519, NULL, msg, sig));
+
+	/* verify with correct signature scheme */
+	ck_assert(pubkey->verify(pubkey, SIGN_ED448, NULL, msg, sig));
+
+	/* cleanup */
+	key->destroy(key);
+	pubkey->destroy(pubkey);
+	chunk_free(&sig);
+}
+END_TEST
+
+START_TEST(test_ed448_speed)
+{
+	private_key_t *key;
+	public_key_t *pubkey;
+	chunk_t msg = chunk_from_str("Hello Ed448"), sig;
+	int i, count = 500;
+
+#ifdef HAVE_CLOCK_GETTIME
+	struct timespec start, stop;
+	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
+#endif
+
+	for (i = 0; i < count; i++)
+	{
+		key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448,
+								 BUILD_KEY_SIZE, 456, BUILD_END);
+		ck_assert(key != NULL);
+		ck_assert(key->sign(key, SIGN_ED448, NULL, msg, &sig));
+		pubkey = key->get_public_key(key);
+		ck_assert(pubkey != NULL);
+		ck_assert(pubkey->verify(pubkey, SIGN_ED448, NULL, msg, sig));
+		key->destroy(key);
+		pubkey->destroy(pubkey);
+		chunk_free(&sig);
+	}
+
+#ifdef HAVE_CLOCK_GETTIME
+	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &stop);
+	DBG0(DBG_LIB, "%d Ed448 keys and signatures in %d ms\n", count,
+				  (stop.tv_nsec - start.tv_nsec) / 1000000 +
+				  (stop.tv_sec - start.tv_sec) * 1000);
+#endif
+}
+END_TEST
+
+static chunk_t zero_pk = chunk_from_chars(
+	0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00);
+
+/* sig_tests[0].sig with s+L, note that only the 9 most significant bits are 0 */
+static chunk_t malleable_sig = chunk_from_chars(
+	0x53,0x3a,0x37,0xf6,0xbb,0xe4,0x57,0x25,0x1f,0x02,0x3c,0x0d,0x88,0xf9,0x76,0xae,
+	0x2d,0xfb,0x50,0x4a,0x84,0x3e,0x34,0xd2,0x07,0x4f,0xd8,0x23,0xd4,0x1a,0x59,0x1f,
+	0x2b,0x23,0x3f,0x03,0x4f,0x62,0x82,0x81,0xf2,0xfd,0x7a,0x22,0xdd,0xd4,0x7d,0x78,
+	0x28,0xc5,0x9b,0xd0,0xa2,0x1b,0xfd,0x39,0x80,0xf2,0x52,0x78,0xd3,0x66,0x74,0x03,
+	0xc1,0x4b,0xce,0xc5,0xf9,0xcf,0xde,0x99,0x55,0xeb,0xc8,0x33,0x3c,0x0a,0xe7,0x8f,
+	0xc8,0x6e,0x51,0x83,0x17,0xc5,0xc7,0xcd,0xda,0x85,0x30,0xa1,0x13,0xa0,0xf4,0xdb,
+	0xb6,0x11,0x49,0xf0,0x5a,0x73,0x63,0x26,0x8c,0x71,0xd9,0x58,0x08,0xff,0x2e,0x65,
+	0x66,0x00);
+
+START_TEST(test_ed448_fail)
+{
+	private_key_t *key;
+	public_key_t *pubkey;
+	chunk_t blob, sig;
+	uint8_t sig1[114];
+
+	/* Invalid private key format */
+	key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448,
+					BUILD_BLOB_ASN1_DER, chunk_empty, BUILD_END);
+	ck_assert(key == NULL);
+
+	key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448,
+					BUILD_EDDSA_PRIV_ASN1_DER, chunk_empty, BUILD_END);
+	ck_assert(key == NULL);
+
+	blob = chunk_from_chars(0x04, 0x01, 0x9d);
+	key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448,
+					BUILD_EDDSA_PRIV_ASN1_DER, blob, BUILD_END);
+	ck_assert(key == NULL);
+
+	/* Invalid public key format */
+	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+					BUILD_BLOB_ASN1_DER, chunk_empty, BUILD_END);
+	ck_assert(pubkey == NULL);
+
+	blob = chunk_from_chars(0x30, 0x0b, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
+							0x71, 0x03, 0x02, 0x00, 0xd7);
+	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+					BUILD_BLOB_ASN1_DER, blob, BUILD_END);
+	ck_assert(pubkey == NULL);
+
+	blob = chunk_from_chars(0x30, 0x0b, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x00,
+							0x71, 0x03, 0x02, 0x00, 0xd7);
+	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+					BUILD_BLOB_ASN1_DER, blob, BUILD_END);
+	ck_assert(pubkey == NULL);
+
+	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+					BUILD_KEY_SIZE, 456, BUILD_BLOB_ASN1_DER, blob, BUILD_END);
+	ck_assert(pubkey == NULL);
+
+	/* Invalid signature format */
+	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+					BUILD_BLOB_ASN1_DER, sig_tests[0].pubkey, BUILD_END);
+	ck_assert(pubkey != NULL);
+
+	ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, chunk_empty,
+							  chunk_empty));
+
+	/* RFC 8032, section 5.2.7 requires that 0 <= s < L to prevent signature
+	 * malleability.  Only a warning because OpenSSL is vulnerable to this. */
+	if (pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg,
+					   malleable_sig))
+	{
+		warn("Ed448 signature verification is vulnerable to malleable "
+			 "signatures");
+	}
+
+	/* malformed signature */
+	sig = chunk_from_thing(sig1);
+	memcpy(sig1, sig_tests[0].sig.ptr, sig_tests[0].sig.len);
+	sig1[113] |= 0xFF;
+	ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg,
+							  sig));
+
+	/* wrong signature */
+	memcpy(sig1, sig_tests[0].sig.ptr, sig_tests[0].sig.len);
+	sig1[0] = 0xe4;
+	ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg,
+							  sig));
+
+	/* detect all-zeroes public key */
+	pubkey->destroy(pubkey);
+	pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
+					BUILD_BLOB_ASN1_DER, zero_pk, BUILD_END);
+	ck_assert(pubkey != NULL);
+	ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg,
+							  sig));
+	pubkey->destroy(pubkey);
+}
+END_TEST
+
+Suite *ed448_suite_create()
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("ed448");
+
+	tc = tcase_create("ed448_sign");
+	tcase_add_loop_test(tc, test_ed448_sign, 0, countof(sig_tests));
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("ed448_gen");
+	tcase_add_test(tc, test_ed448_gen);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("ed448_fail");
+	tcase_add_test(tc, test_ed448_fail);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("ed448_speed");
+	test_case_set_timeout(tc, 10);
+	tcase_add_test(tc, test_ed448_speed);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/src/libstrongswan/tests/suites/test_rsa.c b/src/libstrongswan/tests/suites/test_rsa.c
index e6dc7744a..a71fa0ce5 100644
--- a/src/libstrongswan/tests/suites/test_rsa.c
+++ b/src/libstrongswan/tests/suites/test_rsa.c
@@ -40,7 +40,7 @@ static signature_scheme_t schemes[] = {
 static rsa_pss_params_t default_pss_params = {
 	.hash = HASH_SHA256,
 	.mgf1_hash = HASH_SHA256,
-	.salt_len = RSA_PSS_SALT_LEN_DEFAULT,
+	.salt_len = HASH_SIZE_SHA256,
 };
 
 /**
diff --git a/src/libstrongswan/tests/suites/test_signature_params.c b/src/libstrongswan/tests/suites/test_signature_params.c
index 38cb5803f..cbf1a2861 100644
--- a/src/libstrongswan/tests/suites/test_signature_params.c
+++ b/src/libstrongswan/tests/suites/test_signature_params.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Tobias Brunner
+ * Copyright (C) 2017-2018 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -138,27 +138,27 @@ static struct {
 					   0xa1,0x1c,0x30,0x1a,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x08,0x30,
 					   0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0xa2,0x03,
 					   0x02,0x01,0x20),
-		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = HASH_SIZE_SHA256, }},
 	/* default salt length: SHA-1 */
 	{ chunk_from_chars(0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x00),
-		{ .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
+		{ .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, }},
 	/* default salt length: SHA-224 */
 	{ chunk_from_chars(0x30,0x23,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x16,0xa0,
 					   0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,
 					   0xa2,0x03,0x02,0x01,0x1c),
-		{ .hash = HASH_SHA224, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
+		{ .hash = HASH_SHA224, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA224, }},
 	/* default salt length: SHA-384 */
 	{ chunk_from_chars(0x30,0x23,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x16,0xa0,
 					   0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,
 					   0xa2,0x03,0x02,0x01,0x30),
-		{ .hash = HASH_SHA384, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
+		{ .hash = HASH_SHA384, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA384, }},
 	/* SHA-512 */
 	{ chunk_from_chars(0x30,0x41,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x34,0xa0,
 					   0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,
 					   0xa1,0x1c,0x30,0x1a,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x08,0x30,
 					   0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0xa2,0x03,
 					   0x02,0x01,0x40),
-	  { .hash = HASH_SHA512, .mgf1_hash = HASH_SHA512, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
+	  { .hash = HASH_SHA512, .mgf1_hash = HASH_SHA512, .salt_len = HASH_SIZE_SHA512, }},
 	/* SHA-256, no salt */
 	{ chunk_from_chars(0x30,0x41,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x34,0xa0,
 					   0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,
@@ -199,6 +199,8 @@ rsa_pss_params_t rsa_pss_build_invalid_tests[] = {
 	{ .hash = HASH_UNKNOWN, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, },
 	/* invalid mgf */
 	{ .hash = HASH_SHA256, .mgf1_hash = HASH_UNKNOWN, .salt_len = HASH_SIZE_SHA256, },
+	/* undetermined salt */
+	{ .hash = HASH_UNKNOWN, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, },
 };
 
 START_TEST(test_rsa_pss_params_build_invalid)
@@ -209,6 +211,49 @@ START_TEST(test_rsa_pss_params_build_invalid)
 }
 END_TEST
 
+
+static struct {
+	ssize_t expected;
+	size_t modbits;
+	rsa_pss_params_t params;
+} rsa_pss_salt_len_tests[] = {
+	{ HASH_SIZE_SHA256, 0,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
+	{ HASH_SIZE_SHA256, 3072,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
+	{ -1, 0,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
+	{ 0, 256,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
+	{ 350, 3071,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
+	{ 350, 3072,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
+	{ 350, 3073,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
+	{ 478, 4096,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
+	{ 10, 0,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = 10, }},
+	{ 10, 3072,
+		{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = 10, }},
+};
+
+START_TEST(test_rsa_pss_params_set_salt_len)
+{
+	if (rsa_pss_params_set_salt_len(&rsa_pss_salt_len_tests[_i].params,
+									rsa_pss_salt_len_tests[_i].modbits))
+	{
+		ck_assert_int_eq(rsa_pss_salt_len_tests[_i].expected,
+						 rsa_pss_salt_len_tests[_i].params.salt_len);
+	}
+	else
+	{
+		ck_assert(rsa_pss_salt_len_tests[_i].expected < 0);
+	}
+}
+END_TEST
+
 static rsa_pss_params_t rsa_pss_params_sha1 = { .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, };
 static rsa_pss_params_t rsa_pss_params_sha256 = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = HASH_SIZE_SHA256, };
 static rsa_pss_params_t rsa_pss_params_sha256_mgf1 = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA512, .salt_len = HASH_SIZE_SHA256, };
@@ -430,6 +475,10 @@ Suite *signature_params_suite_create()
 	tcase_add_loop_test(tc, test_rsa_pss_params_build_invalid, 0, countof(rsa_pss_build_invalid_tests));
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("rsa/pss salt len");
+	tcase_add_loop_test(tc, test_rsa_pss_params_set_salt_len, 0, countof(rsa_pss_salt_len_tests));
+	suite_add_tcase(s, tc);
+
 	tc = tcase_create("params compare");
 	tcase_add_loop_test(tc, test_params_compare, 0, countof(params_compare_tests));
 	tcase_add_test(tc, test_params_compare_null);
diff --git a/src/libstrongswan/tests/tests.h b/src/libstrongswan/tests/tests.h
index 9fc38d480..26ff161a4 100644
--- a/src/libstrongswan/tests/tests.h
+++ b/src/libstrongswan/tests/tests.h
@@ -52,5 +52,6 @@ TEST_SUITE_DEPEND(mgf1_sha256_suite_create, XOF, XOF_MGF1_SHA256)
 TEST_SUITE_DEPEND(ntru_suite_create, DH, NTRU_112_BIT)
 TEST_SUITE_DEPEND(fetch_http_suite_create, FETCHER, "http://")
 TEST_SUITE_DEPEND(ed25519_suite_create, PRIVKEY_GEN, KEY_ED25519)
+TEST_SUITE_DEPEND(ed448_suite_create, PRIVKEY_GEN, KEY_ED448)
 TEST_SUITE(signature_params_suite_create)
 
diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h
index e60cd8ad0..0dbe9dc80 100644
--- a/src/libstrongswan/utils/chunk.h
+++ b/src/libstrongswan/utils/chunk.h
@@ -332,7 +332,7 @@ static inline bool chunk_equals_ptr(chunk_t *a, chunk_t *b)
 }
 
 /**
- * Increment a chunk, as it would reprensent a network order integer.
+ * Increment a chunk, as it would represent a network order integer.
  *
  * @param chunk			chunk to increment
  * @return				TRUE if an overflow occurred
diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c
index efeb0f478..63b7453f3 100644
--- a/src/libstrongswan/utils/leak_detective.c
+++ b/src/libstrongswan/utils/leak_detective.c
@@ -582,6 +582,16 @@ static char *whitelist[] = {
 	"OPENSSL_init_crypto",
 	"CRYPTO_THREAD_lock_new",
 	"ERR_add_error_data",
+	"ERR_set_mark",
+	"ENGINE_load_builtin_engines",
+	"OPENSSL_load_builtin_modules",
+	"CONF_modules_load_file",
+	"CONF_module_add",
+	"RAND_DRBG_bytes",
+	"RAND_DRBG_generate",
+	"RAND_DRBG_get0_master",
+	"RAND_DRBG_get0_private",
+	"RAND_DRBG_get0_public",
 	/* OpenSSL libssl */
 	"SSL_COMP_get_compression_methods",
 	/* NSPR */
@@ -619,6 +629,7 @@ static char *whitelist[] = {
 	"botan_privkey_create_ecdsa",
 	"botan_privkey_create_ecdh",
 	"botan_privkey_load_ecdh",
+	"botan_privkey_load",
 };
 
 /**
@@ -673,7 +684,8 @@ static int print_traces(private_leak_detective_t *this,
 	int leaks = 0;
 	memory_header_t *hdr;
 	enumerator_t *enumerator;
-	hashtable_t *entries;
+	hashtable_t *entries, *ignored = NULL;
+	backtrace_t *bt;
 	struct {
 		/** associated backtrace */
 		backtrace_t *backtrace;
@@ -688,15 +700,32 @@ static int print_traces(private_leak_detective_t *this,
 
 	entries = hashtable_create((hashtable_hash_t)hash,
 							   (hashtable_equals_t)equals, 1024);
+	if (whitelisted)
+	{
+		ignored = hashtable_create((hashtable_hash_t)hash,
+								   (hashtable_equals_t)equals, 1024);
+	}
+
 	lock->lock(lock);
 	for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
 	{
-		if (whitelisted &&
-			hdr->backtrace->contains_function(hdr->backtrace,
-											  whitelist, countof(whitelist)))
+		if (whitelisted)
 		{
-			(*whitelisted)++;
-			continue;
+			bt = ignored->get(ignored, hdr->backtrace);
+			if (!bt)
+			{
+				if (hdr->backtrace->contains_function(hdr->backtrace, whitelist,
+													  countof(whitelist)))
+				{
+					bt = hdr->backtrace;
+					ignored->put(ignored, bt, bt);
+				}
+			}
+			if (bt)
+			{
+				(*whitelisted)++;
+				continue;
+			}
 		}
 		entry = entries->get(entries, hdr->backtrace);
 		if (entry)
@@ -720,6 +749,7 @@ static int print_traces(private_leak_detective_t *this,
 		leaks++;
 	}
 	lock->unlock(lock);
+	DESTROY_IF(ignored);
 
 	enumerator = entries->create_enumerator(entries);
 	while (enumerator->enumerate(enumerator, NULL, &entry))
-- 
cgit v1.2.3