aboutsummaryrefslogtreecommitdiffstats
path: root/src/libstrongswan/plugins/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/openssl')
-rw-r--r--src/libstrongswan/plugins/openssl/Makefile.am3
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_gcm.c259
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_gcm.h37
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_pkcs7.c3
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_plugin.c17
5 files changed, 317 insertions, 2 deletions
diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am
index f971a5e08..e71567311 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.am
+++ b/src/libstrongswan/plugins/openssl/Makefile.am
@@ -25,7 +25,8 @@ libstrongswan_openssl_la_SOURCES = \
openssl_crl.c openssl_crl.h \
openssl_pkcs7.c openssl_pkcs7.h \
openssl_rng.c openssl_rng.h \
- openssl_hmac.c openssl_hmac.h
+ openssl_hmac.c openssl_hmac.h \
+ openssl_gcm.c openssl_gcm.h
libstrongswan_openssl_la_LDFLAGS = -module -avoid-version
libstrongswan_openssl_la_LIBADD = -lcrypto
diff --git a/src/libstrongswan/plugins/openssl/openssl_gcm.c b/src/libstrongswan/plugins/openssl/openssl_gcm.c
new file mode 100644
index 000000000..fde7ae71d
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_gcm.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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_gcm.h"
+
+#include <openssl/evp.h>
+
+/** as defined in RFC 4106 */
+#define IV_LEN 8
+#define SALT_LEN 4
+#define NONCE_LEN (IV_LEN + SALT_LEN)
+
+typedef struct private_aead_t private_aead_t;
+
+/**
+ * Private data of aead_t
+ */
+struct private_aead_t {
+
+ /**
+ * Public interface
+ */
+ aead_t public;
+
+ /**
+ * The encryption key
+ */
+ chunk_t key;
+
+ /**
+ * Salt value
+ */
+ char salt[SALT_LEN];
+
+ /**
+ * Size of the integrity check value
+ */
+ size_t icv_size;
+
+ /**
+ * The cipher to use
+ */
+ const EVP_CIPHER *cipher;
+};
+
+/**
+ * Do the actual en/decryption in an EVP context
+ */
+static bool crypt(private_aead_t *this, chunk_t data, chunk_t assoc, chunk_t iv,
+ u_char *out, int enc)
+{
+ EVP_CIPHER_CTX ctx;
+ u_char nonce[NONCE_LEN];
+ bool success = FALSE;
+ int len;
+
+ memcpy(nonce, this->salt, SALT_LEN);
+ memcpy(nonce + SALT_LEN, iv.ptr, IV_LEN);
+
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ if (!EVP_CipherInit_ex(&ctx, this->cipher, NULL, NULL, NULL, enc) ||
+ !EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, NONCE_LEN, NULL) ||
+ !EVP_CipherInit_ex(&ctx, NULL, NULL, this->key.ptr, nonce, enc))
+ {
+ goto done;
+ }
+ if (!enc && !EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, this->icv_size,
+ data.ptr + data.len))
+ { /* set ICV for verification on decryption */
+ goto done;
+ }
+ if (assoc.len && !EVP_CipherUpdate(&ctx, NULL, &len, assoc.ptr, assoc.len))
+ { /* set AAD if specified */
+ goto done;
+ }
+ if (!EVP_CipherUpdate(&ctx, out, &len, data.ptr, data.len) ||
+ !EVP_CipherFinal_ex(&ctx, out + len, &len))
+ { /* EVP_CipherFinal_ex fails if ICV is incorrect on decryption */
+ goto done;
+ }
+ if (enc && !EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, this->icv_size,
+ out + data.len))
+ { /* copy back the ICV when encrypting */
+ goto done;
+ }
+ success = TRUE;
+
+done:
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return success;
+}
+
+METHOD(aead_t, encrypt, bool,
+ private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
+ chunk_t *encrypted)
+{
+ u_char *out;
+
+ out = plain.ptr;
+ if (encrypted)
+ {
+ *encrypted = chunk_alloc(plain.len + this->icv_size);
+ out = encrypted->ptr;
+ }
+ return crypt(this, plain, assoc, iv, out, 1);
+}
+
+METHOD(aead_t, decrypt, bool,
+ private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
+ chunk_t *plain)
+{
+ u_char *out;
+
+ if (encrypted.len < this->icv_size)
+ {
+ return FALSE;
+ }
+ encrypted.len -= this->icv_size;
+
+ out = encrypted.ptr;
+ if (plain)
+ {
+ *plain = chunk_alloc(encrypted.len);
+ out = plain->ptr;
+ }
+ return crypt(this, encrypted, assoc, iv, out, 0);
+}
+
+METHOD(aead_t, get_block_size, size_t,
+ private_aead_t *this)
+{
+ return this->cipher->block_size;
+}
+
+METHOD(aead_t, get_icv_size, size_t,
+ private_aead_t *this)
+{
+ return this->icv_size;
+}
+
+METHOD(aead_t, get_iv_size, size_t,
+ private_aead_t *this)
+{
+ return IV_LEN;
+}
+
+METHOD(aead_t, get_key_size, size_t,
+ private_aead_t *this)
+{
+ return this->key.len + SALT_LEN;
+}
+
+METHOD(aead_t, set_key, bool,
+ private_aead_t *this, chunk_t key)
+{
+ if (key.len != get_key_size(this))
+ {
+ return FALSE;
+ }
+ memcpy(this->salt, key.ptr + key.len - SALT_LEN, SALT_LEN);
+ memcpy(this->key.ptr, key.ptr, this->key.len);
+ return TRUE;
+}
+
+METHOD(aead_t, destroy, void,
+ private_aead_t *this)
+{
+ chunk_clear(&this->key);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+aead_t *openssl_gcm_create(encryption_algorithm_t algo, size_t key_size)
+{
+ private_aead_t *this;
+
+ INIT(this,
+ .public = {
+ .encrypt = _encrypt,
+ .decrypt = _decrypt,
+ .get_block_size = _get_block_size,
+ .get_icv_size = _get_icv_size,
+ .get_iv_size = _get_iv_size,
+ .get_key_size = _get_key_size,
+ .set_key = _set_key,
+ .destroy = _destroy,
+ },
+ );
+
+ switch (algo)
+ {
+ case ENCR_AES_GCM_ICV8:
+ this->icv_size = 8;
+ break;
+ case ENCR_AES_GCM_ICV12:
+ this->icv_size = 12;
+ break;
+ case ENCR_AES_GCM_ICV16:
+ this->icv_size = 16;
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+
+ switch (algo)
+ {
+ case ENCR_AES_GCM_ICV8:
+ case ENCR_AES_GCM_ICV12:
+ case ENCR_AES_GCM_ICV16:
+ switch (key_size)
+ {
+ case 0:
+ key_size = 16;
+ /* FALL */
+ case 16:
+ this->cipher = EVP_get_cipherbyname("aes-128-gcm");
+ break;
+ case 24:
+ this->cipher = EVP_get_cipherbyname("aes-192-gcm");
+ break;
+ case 32:
+ this->cipher = EVP_get_cipherbyname("aes-256-gcm");
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+
+ if (!this->cipher)
+ {
+ free(this);
+ return NULL;
+ }
+
+ this->key = chunk_alloc(key_size);
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/plugins/openssl/openssl_gcm.h b/src/libstrongswan/plugins/openssl/openssl_gcm.h
new file mode 100644
index 000000000..12d2e8ab6
--- /dev/null
+++ b/src/libstrongswan/plugins/openssl/openssl_gcm.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * 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.
+ */
+
+/**
+ * Implements the aead_t interface using OpenSSL in GCM mode.
+ *
+ * @defgroup openssl_gcm openssl_gcm
+ * @{ @ingroup openssl_p
+ */
+
+#ifndef OPENSSL_GCM_H_
+#define OPENSSL_GCM_H_
+
+#include <crypto/aead.h>
+
+/**
+ * Constructor to create aead_t implementation.
+ *
+ * @param algo algorithm to implement
+ * @param key_size key size in bytes
+ * @return aead_t object, NULL if not supported
+ */
+aead_t *openssl_gcm_create(encryption_algorithm_t algo, size_t key_size);
+
+#endif /** OPENSSL_GCM_H_ @}*/
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
index ccc426235..9c3c4040c 100644
--- a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
@@ -13,8 +13,10 @@
* for more details.
*/
+#include <openssl/opensslv.h>
#include <openssl/opensslconf.h>
+#if OPENSSL_VERSION_NUMBER >= 0x0090807fL
#ifndef OPENSSL_NO_CMS
#include "openssl_pkcs7.h"
@@ -788,3 +790,4 @@ pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args)
}
#endif /* OPENSSL_NO_CMS */
+#endif /* OPENSSL_VERSION_NUMBER */
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c
index dd6a379d2..282fe2b1b 100644
--- a/src/libstrongswan/plugins/openssl/openssl_plugin.c
+++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c
@@ -43,6 +43,7 @@
#include "openssl_pkcs7.h"
#include "openssl_rng.h"
#include "openssl_hmac.h"
+#include "openssl_gcm.h"
typedef struct private_openssl_plugin_t private_openssl_plugin_t;
@@ -304,6 +305,19 @@ METHOD(plugin_t, get_features, int,
PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256),
#endif
#endif /* OPENSSL_NO_HMAC */
+#ifndef OPENSSL_NO_AES
+ /* AES GCM */
+ PLUGIN_REGISTER(AEAD, openssl_gcm_create),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8, 16),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8, 24),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8, 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_ICV16, 16),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 24),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 32),
+#endif /* OPENSSL_NO_AES */
#ifndef OPENSSL_NO_DH
/* MODP DH groups */
PLUGIN_REGISTER(DH, openssl_diffie_hellman_create),
@@ -366,10 +380,12 @@ METHOD(plugin_t, get_features, int,
PLUGIN_SDEPEND(PUBKEY, KEY_DSA),
PLUGIN_REGISTER(CERT_DECODE, openssl_crl_load, TRUE),
PLUGIN_PROVIDE(CERT_DECODE, CERT_X509_CRL),
+#if OPENSSL_VERSION_NUMBER >= 0x0090807fL
#ifndef OPENSSL_NO_CMS
PLUGIN_REGISTER(CONTAINER_DECODE, openssl_pkcs7_load, TRUE),
PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS7),
#endif /* OPENSSL_NO_CMS */
+#endif /* OPENSSL_VERSION_NUMBER */
#ifndef OPENSSL_NO_ECDH
/* EC DH groups */
PLUGIN_REGISTER(DH, openssl_ec_diffie_hellman_create),
@@ -470,4 +486,3 @@ plugin_t *openssl_plugin_create()
return &this->public.plugin;
}
-