summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2019-01-02 10:45:36 +0100
committerYves-Alexis Perez <corsac@debian.org>2019-01-02 11:07:05 +0100
commit918094fde55fa0dbfd59a5f88d576efb513a88db (patch)
tree61e31656c60a6cc928c50cd633568043673e2cbd /src/libstrongswan/plugins
parent69bc96f6b0b388d35e983f8d27224fa49d92918c (diff)
downloadvyos-strongswan-918094fde55fa0dbfd59a5f88d576efb513a88db.tar.gz
vyos-strongswan-918094fde55fa0dbfd59a5f88d576efb513a88db.zip
New upstream version 5.7.2
Diffstat (limited to 'src/libstrongswan/plugins')
-rw-r--r--src/libstrongswan/plugins/agent/agent_private_key.c133
-rw-r--r--src/libstrongswan/plugins/botan/Makefile.am4
-rw-r--r--src/libstrongswan/plugins/botan/Makefile.in13
-rw-r--r--src/libstrongswan/plugins/botan/botan_aead.c (renamed from src/libstrongswan/plugins/botan/botan_gcm.c)219
-rw-r--r--src/libstrongswan/plugins/botan/botan_aead.h (renamed from src/libstrongswan/plugins/botan/botan_gcm.h)17
-rw-r--r--src/libstrongswan/plugins/botan/botan_crypter.c6
-rw-r--r--src/libstrongswan/plugins/botan/botan_ec_public_key.c19
-rw-r--r--src/libstrongswan/plugins/botan/botan_ed_private_key.c279
-rw-r--r--src/libstrongswan/plugins/botan/botan_ed_private_key.h63
-rw-r--r--src/libstrongswan/plugins/botan/botan_ed_public_key.c202
-rw-r--r--src/libstrongswan/plugins/botan/botan_ed_public_key.h51
-rw-r--r--src/libstrongswan/plugins/botan/botan_plugin.c77
-rw-r--r--src/libstrongswan/plugins/botan/botan_rsa_private_key.c24
-rw-r--r--src/libstrongswan/plugins/botan/botan_rsa_public_key.c66
-rw-r--r--src/libstrongswan/plugins/botan/botan_util.c35
-rw-r--r--src/libstrongswan/plugins/botan/botan_util.h12
-rw-r--r--src/libstrongswan/plugins/botan/botan_util_keys.c38
-rw-r--r--src/libstrongswan/plugins/curve25519/curve25519_public_key.c110
-rw-r--r--src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c4
-rw-r--r--src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c6
-rw-r--r--src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c6
-rw-r--r--src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c6
-rw-r--r--src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c7
-rw-r--r--src/libstrongswan/plugins/mysql/mysql_database.c10
-rw-r--r--src/libstrongswan/plugins/openssl/Makefile.am5
-rw-r--r--src/libstrongswan/plugins/openssl/Makefile.in11
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_crl.c21
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ed_private_key.c356
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ed_private_key.h58
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ed_public_key.c304
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ed_public_key.h38
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_plugin.c53
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rng.c11
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c7
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c7
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_util.c8
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_util.h4
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_x509.c14
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c256
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h37
-rw-r--r--src/libstrongswan/plugins/sshkey/sshkey_builder.c35
-rw-r--r--src/libstrongswan/plugins/sshkey/sshkey_encoder.c38
-rw-r--r--src/libstrongswan/plugins/test_vectors/Makefile.am1
-rw-r--r--src/libstrongswan/plugins/test_vectors/Makefile.in7
-rw-r--r--src/libstrongswan/plugins/test_vectors/test_vectors.h2
-rw-r--r--src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c40
-rw-r--r--src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c2
-rw-r--r--src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c43
48 files changed, 2480 insertions, 285 deletions
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
@@ -82,6 +82,14 @@ enum agent_msg_type_t {
};
/**
+ * 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
*/
static u_char read_byte(chunk_t *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_gcm.c b/src/libstrongswan/plugins/botan/botan_aead.c
index 7e0fc1468..40006ae77 100644
--- a/src/libstrongswan/plugins/botan/botan_gcm.c
+++ b/src/libstrongswan/plugins/botan/botan_aead.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2018 Atanas Filyanov
* Rohde & Schwarz Cybersecurity GmbH
*
@@ -21,23 +24,28 @@
* THE SOFTWARE.
*/
-#include "botan_gcm.h"
+#include "botan_aead.h"
#include <botan/build.h>
-#ifdef BOTAN_HAS_AES
-#ifdef BOTAN_HAS_AEAD_GCM
+#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
+ * As defined in RFC 4106 (GCM) and RFC 7634 (ChaPoly)
*/
-#define IV_LEN 8
-#define SALT_LEN 4
-#define NONCE_LEN (IV_LEN + SALT_LEN)
+#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;
@@ -56,7 +64,7 @@ struct private_aead_t {
/**
* Salt value
*/
- char salt[SALT_LEN];
+ chunk_t salt;
/**
* Size of the integrity check value
@@ -77,15 +85,12 @@ struct private_aead_t {
/**
* 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)
+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;
- 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);
+ chunk_t nonce;
if (botan_cipher_init(&cipher, this->cipher_name, init_flag))
{
@@ -105,7 +110,9 @@ static bool crypt(private_aead_t *this, chunk_t data, chunk_t assoc, chunk_t iv,
return FALSE;
}
- if (botan_cipher_start(cipher, nonce, NONCE_LEN))
+ nonce = chunk_cata("cc", this->salt, iv);
+
+ if (botan_cipher_start(cipher, nonce.ptr, nonce.len))
{
botan_cipher_destroy(cipher);
return FALSE;
@@ -149,7 +156,8 @@ METHOD(aead_t, encrypt, bool,
*encrypted = chunk_alloc(plain.len + this->icv_size);
out = encrypted->ptr;
}
- return crypt(this, plain, assoc, iv, out, BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
+ return do_crypt(this, plain, assoc, iv, out,
+ BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
}
METHOD(aead_t, decrypt, bool,
@@ -170,8 +178,8 @@ METHOD(aead_t, decrypt, bool,
*plain = chunk_alloc(encrypted.len);
out = plain->ptr;
}
- return crypt(this, encrypted, assoc, iv, out,
- BOTAN_CIPHER_INIT_FLAG_DECRYPT);
+ return do_crypt(this, encrypted, assoc, iv, out,
+ BOTAN_CIPHER_INIT_FLAG_DECRYPT);
}
METHOD(aead_t, get_block_size, size_t,
@@ -201,7 +209,7 @@ METHOD(aead_t, get_iv_gen, iv_gen_t*,
METHOD(aead_t, get_key_size, size_t,
private_aead_t *this)
{
- return this->key.len + SALT_LEN;
+ return this->key.len + this->salt.len;
}
METHOD(aead_t, set_key, bool,
@@ -211,7 +219,7 @@ METHOD(aead_t, set_key, bool,
{
return FALSE;
}
- memcpy(this->salt, key.ptr + key.len - SALT_LEN, SALT_LEN);
+ 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;
}
@@ -220,15 +228,82 @@ 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_gcm_create(encryption_algorithm_t algo, size_t key_size,
- size_t salt_size)
+aead_t *botan_aead_create(encryption_algorithm_t algo, size_t key_size,
+ size_t salt_size)
{
private_aead_t *this;
@@ -246,88 +321,68 @@ aead_t *botan_gcm_create(encryption_algorithm_t algo, size_t key_size,
},
);
- if (salt_size && salt_size != SALT_LEN)
- {
- /* currently not supported */
- free(this);
- return NULL;
- }
-
switch (algo)
{
+#ifdef BOTAN_HAS_AES
+#ifdef BOTAN_HAS_AEAD_GCM
case ENCR_AES_GCM_ICV8:
- switch (key_size)
+ case ENCR_AES_GCM_ICV12:
+ case ENCR_AES_GCM_ICV16:
+ if (!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;
+ key_size = 16;
+ }
+ if (!check_salt_size(SALT_LEN, &salt_size) ||
+ !determine_aes_params(this, algo, key_size))
+ {
+ free(this);
+ return NULL;
}
- this->icv_size = 8;
break;
- case ENCR_AES_GCM_ICV12:
- switch (key_size)
+#endif
+#ifdef BOTAN_HAS_AEAD_CCM
+ case ENCR_AES_CCM_ICV8:
+ case ENCR_AES_CCM_ICV12:
+ case ENCR_AES_CCM_ICV16:
+ if (!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;
+ key_size = 16;
+ }
+ if (!check_salt_size(CCM_SALT_LEN, &salt_size) ||
+ !determine_aes_params(this, algo, key_size))
+ {
+ free(this);
+ return NULL;
}
- this->icv_size = 12;
break;
- case ENCR_AES_GCM_ICV16:
- switch (key_size)
+#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))
{
- 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;
+ 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
-#endif
diff --git a/src/libstrongswan/plugins/botan/botan_gcm.h b/src/libstrongswan/plugins/botan/botan_aead.h
index b2053cb4d..00a2ba4bc 100644
--- a/src/libstrongswan/plugins/botan/botan_gcm.h
+++ b/src/libstrongswan/plugins/botan/botan_aead.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2018 Atanas Filyanov
* Rohde & Schwarz Cybersecurity GmbH
*
@@ -22,14 +25,14 @@
*/
/**
- * Implements the aead_t interface using Botan in GCM mode.
+ * Implements the aead_t interface using Botan.
*
- * @defgroup botan_gcm botan_gcm
+ * @defgroup botan_aead botan_aead
* @{ @ingroup botan_p
*/
-#ifndef BOTAN_GCM_H_
-#define BOTAN_GCM_H_
+#ifndef BOTAN_AEAD_H_
+#define BOTAN_AEAD_H_
#include <crypto/aead.h>
@@ -41,7 +44,7 @@
* @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);
+aead_t *botan_aead_create(encryption_algorithm_t algo, size_t key_size,
+ size_t salt_size);
-#endif /** BOTAN_GCM_H_ @}*/
+#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_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
@@ -177,6 +215,9 @@ METHOD(plugin_t, get_features, int,
#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),
#ifdef BOTAN_HAS_RSA
@@ -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
@@ -69,33 +70,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
*/
static bool verify_emsa_pss_signature(private_botan_rsa_public_key_t *this,
@@ -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;
}
@@ -252,6 +261,32 @@ bool botan_get_signature(botan_privkey_t key, const char *scheme,
/*
* 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
+ */
bool botan_dh_key_derivation(botan_privkey_t key, chunk_t pub, chunk_t *secret)
{
botan_pk_op_ka_t ka;
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
@@ -101,6 +101,18 @@ 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)
@@ -200,22 +222,68 @@ static const asn1Object_t pubkeyObjects[] = {
#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.
*/
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,10 +16,40 @@
#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"
"\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0"
@@ -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",
+};