gcrypt: Remove limited crypto plugin

This has not seen any significant changes for years.  So it lacks support
for modern algorithms and would require quite some work for an overhaul.
Given that we support several other crypto backends, let's just remove
this to reduce the maintenance burden.

The test scenarios and other references are also removed.
This commit is contained in:
Tobias Brunner
2026-07-27 08:09:39 +02:00
parent 248c915593
commit 7d122d5a98
69 changed files with 9 additions and 3334 deletions
-81
View File
@@ -1,81 +0,0 @@
AES_CTR[gcrypt]
AES_CTR[gcrypt]
AES_CTR[gcrypt]
AES_CBC[gcrypt]
AES_CBC[gcrypt]
AES_CBC[gcrypt]
AES_ECB[gcrypt]
AES_ECB[gcrypt]
AES_ECB[gcrypt]
AES_CFB[gcrypt]
AES_CFB[gcrypt]
AES_CFB[gcrypt]
BLOWFISH_CBC[gcrypt]
CAMELLIA_CTR[gcrypt]
CAMELLIA_CTR[gcrypt]
CAMELLIA_CTR[gcrypt]
CAMELLIA_CBC[gcrypt]
CAMELLIA_CBC[gcrypt]
CAMELLIA_CBC[gcrypt]
CAST_CBC[gcrypt]
3DES_CBC[gcrypt]
DES_CBC[gcrypt]
DES_ECB[gcrypt]
SERPENT_CBC[gcrypt]
SERPENT_CBC[gcrypt]
SERPENT_CBC[gcrypt]
TWOFISH_CBC[gcrypt]
TWOFISH_CBC[gcrypt]
AES_GCM_8[gcm]
AES_GCM_8[gcm]
AES_GCM_8[gcm]
AES_GCM_12[gcm]
AES_GCM_12[gcm]
AES_GCM_12[gcm]
AES_GCM_16[gcm]
AES_GCM_16[gcm]
AES_GCM_16[gcm]
HMAC_SHA1_96[hmac]
HMAC_SHA1_128[hmac]
HMAC_SHA1_160[hmac]
HMAC_MD5_96[hmac]
HMAC_MD5_128[hmac]
HMAC_SHA2_256_128[hmac]
HMAC_SHA2_256_256[hmac]
HMAC_SHA2_384_192[hmac]
HMAC_SHA2_384_384[hmac]
HMAC_SHA2_512_256[hmac]
HMAC_SHA2_512_512[hmac]
HASH_MD4[gcrypt]
HASH_MD5[gcrypt]
HASH_SHA1[gcrypt]
HASH_SHA2_224[gcrypt]
HASH_SHA2_256[gcrypt]
HASH_SHA2_384[gcrypt]
HASH_SHA2_512[gcrypt]
HASH_IDENTITY[curve25519]
PRF_HMAC_SHA1[hmac]
PRF_HMAC_MD5[hmac]
PRF_HMAC_SHA2_256[hmac]
PRF_HMAC_SHA2_384[hmac]
PRF_HMAC_SHA2_512[hmac]
KDF_PRF[kdf]
KDF_PRF_PLUS[kdf]
RNG_WEAK[gcrypt]
RNG_STRONG[gcrypt]
RNG_STRONG[random]
RNG_TRUE[gcrypt]
RNG_TRUE[random]
MODP_3072[gcrypt]
MODP_4096[gcrypt]
MODP_6144[gcrypt]
MODP_8192[gcrypt]
MODP_2048[gcrypt]
MODP_2048_224[gcrypt]
MODP_2048_256[gcrypt]
MODP_1536[gcrypt]
MODP_1024[gcrypt]
MODP_1024_160[gcrypt]
MODP_768[gcrypt]
MODP_CUSTOM[gcrypt]
CURVE_25519[curve25519]
+1 -1
View File
@@ -164,7 +164,7 @@ jobs:
strategy:
fail-fast: false
matrix:
test: [ botan, wolfssl, openssl-sys, openssl-3, openssl-4, openssl-awslc, gcrypt ]
test: [ botan, wolfssl, openssl-sys, openssl-3, openssl-4, openssl-awslc ]
os: [ ubuntu-latest, ubuntu-22.04 ]
exclude:
# test custom-built libs only on the latest platform
-2
View File
@@ -59,8 +59,6 @@ Contents
https://botan.randombit.net
* The GNU Multiprecision Arithmetic Library (GMP, libgmp)
https://gmplib.org
* The GNU Cryptographic Library (libgcrypt)
https://www.gnupg.org
If no other options are specified during ./configure libgmp will be used.
-1
View File
@@ -56,7 +56,6 @@ plugins = \
plugins/error-notify.opt \
plugins/ext-auth.opt \
plugins/forecast.opt \
plugins/gcrypt.opt \
plugins/ha.opt \
plugins/imc-attestation.opt \
plugins/imc-hcd.opt \
-2
View File
@@ -1,2 +0,0 @@
charon.plugins.gcrypt.quick_random = no
Use faster random numbers in gcrypt; for testing only, produces weak keys!
-18
View File
@@ -138,7 +138,6 @@ ARG_ENABL_SET([des], [enable DES/3DES software implementation plugin.
ARG_DISBL_SET([drbg], [disable the NIST Deterministic Random Bit Generator plugin.])
ARG_ENABL_SET([fips-prf], [enable FIPS PRF software implementation plugin.])
ARG_ENABL_SET([gcm], [enable the GCM AEAD wrapper crypto plugin.])
ARG_ENABL_SET([gcrypt], [enables the libgcrypt plugin.])
ARG_ENABL_SET([gmp], [enable GNU MP (libgmp) based crypto implementation plugin.])
ARG_ENABL_SET([curve25519], [enable Curve25519 Diffie-Hellman plugin.])
ARG_ENABL_SET([hmac], [enable HMAC crypto implementation plugin.])
@@ -1159,20 +1158,6 @@ if test x$wolfssl = xtrue; then
AC_SUBST(wolfssl_LIBS)
fi
if test x$gcrypt = xtrue; then
AC_CHECK_LIB([gcrypt],[gcry_control],[LIBS="$LIBS"],[AC_MSG_ERROR([gcrypt library not found])],[-lgpg-error])
AC_CHECK_HEADER([gcrypt.h],,[AC_MSG_ERROR([gcrypt header gcrypt.h not found!])])
AC_MSG_CHECKING([gcrypt CAMELLIA cipher])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <gcrypt.h>]],
[[enum gcry_cipher_algos alg = GCRY_CIPHER_CAMELLIA128;]])],
[AC_MSG_RESULT([yes]);
AC_DEFINE([HAVE_GCRY_CIPHER_CAMELLIA], [], [have GCRY_CIPHER_CAMELLIA128])],
[AC_MSG_RESULT([no])]
)
fi
if test x$botan = xtrue; then
PKG_CHECK_MODULES(botan, [botan-3], [],
[PKG_CHECK_MODULES(botan, [botan-2])])
@@ -1518,7 +1503,6 @@ ADD_PLUGIN([ipseckey], [c charon])
ADD_PLUGIN([pem], [s charon swanctl pki scripts attest nm cmd aikgen fd fc])
ADD_PLUGIN([openssl], [s charon swanctl pki scripts attest nm cmd aikgen fd])
ADD_PLUGIN([wolfssl], [s charon swanctl pki scripts attest nm cmd aikgen])
ADD_PLUGIN([gcrypt], [s charon swanctl pki scripts attest nm cmd aikgen])
ADD_PLUGIN([botan], [s charon swanctl pki scripts attest nm cmd aikgen])
ADD_PLUGIN([pkcs8], [s charon swanctl pki scripts attest nm cmd])
ADD_PLUGIN([fips-prf], [s charon nm cmd])
@@ -1681,7 +1665,6 @@ AM_CONDITIONAL(USE_MYSQL, test x$mysql = xtrue)
AM_CONDITIONAL(USE_SQLITE, test x$sqlite = xtrue)
AM_CONDITIONAL(USE_OPENSSL, test x$openssl = xtrue)
AM_CONDITIONAL(USE_WOLFSSL, test x$wolfssl = xtrue)
AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue)
AM_CONDITIONAL(USE_BOTAN, test x$botan = xtrue)
AM_CONDITIONAL(USE_AGENT, test x$agent = xtrue)
AM_CONDITIONAL(USE_PKCS11, test x$pkcs11 = xtrue)
@@ -1963,7 +1946,6 @@ AC_CONFIG_FILES([
src/libstrongswan/plugins/sqlite/Makefile
src/libstrongswan/plugins/openssl/Makefile
src/libstrongswan/plugins/wolfssl/Makefile
src/libstrongswan/plugins/gcrypt/Makefile
src/libstrongswan/plugins/botan/Makefile
src/libstrongswan/plugins/agent/Makefile
src/libstrongswan/plugins/pkcs11/Makefile
+4 -7
View File
@@ -11,15 +11,12 @@ function modptest {
}
echo "testing gmp"
# gmp needs an RNG plugin, pick gcrypt
modptest "gmp gcrypt"
# gmp needs an RNG plugin, pick random
modptest "gmp random"
echo "testing curve25519"
# curve25519 needs an RNG plugin, pick gcrypt
$DIR/dh_speed "curve25519 gcrypt" 300 curve25519 curve25519 | tail -n 1
echo "testing gcrypt"
modptest "gcrypt"
# curve25519 needs an RNG plugin, pick random
$DIR/dh_speed "curve25519 random" 300 curve25519 curve25519 | tail -n 1
echo "testing openssl"
modptest "openssl"
+1 -2
View File
@@ -32,8 +32,7 @@ function ecdsatestall {
ecdsatest secp521r1 "$1" 500
}
rsatestall "gmp gcrypt pem pkcs1"
rsatestall "gcrypt pem pkcs1"
rsatestall "gmp random pem pkcs1"
rsatestall "openssl pem"
rsatestall "botan pem"
ecdsatestall "openssl pem"
+2 -7
View File
@@ -225,11 +225,6 @@ openssl*)
TESTS_PLUGINS="$TESTS_PLUGINS kdf"
fi
;;
gcrypt)
CONFIG="--disable-defaults --enable-pki --enable-gcrypt --enable-random --enable-pem --enable-pkcs1 --enable-pkcs8 --enable-gcm --enable-hmac --enable-kdf --enable-curve25519 --enable-x509 --enable-constraints"
export TESTS_PLUGINS="test-vectors gcrypt! random pem pkcs1 pkcs8 gcm hmac kdf curve25519 x509 constraints"
DEPS="libgcrypt20-dev"
;;
botan)
CONFIG="--disable-defaults --enable-pki --enable-botan --enable-pem --enable-hmac --enable-x509 --enable-constraints --enable-drbg"
export TESTS_PLUGINS="test-vectors botan! pem hmac x509 constraints drbg"
@@ -280,7 +275,7 @@ all|alpine|codeql|coverage|sonarcloud|no-dbg|no-testable-ke)
DEPS="$DEPS libcurl4-gnutls-dev libsoup-3.0-dev libunbound-dev libldns-dev
libmysqlclient-dev libsqlite3-dev
libldap2-dev libpcsclite-dev libpam0g-dev binutils-dev libnm-dev
libgcrypt20-dev libjson-c-dev libtspi-dev libsystemd-dev
libjson-c-dev libtspi-dev libsystemd-dev
libselinux1-dev libiptc-dev ruby-rubygems python3-build tox"
if [ "$ID" = "ubuntu" -a "$VERSION_ID" = "22.04" -a "$1" = "build-deps" ]; then
# python3-build is broken on 22.04 with venv (https://bugs.launchpad.net/ubuntu/+source/python-build/+bug/1992108)
@@ -292,7 +287,7 @@ all|alpine|codeql|coverage|sonarcloud|no-dbg|no-testable-ke)
# override the whole list for alpine
DEPS="git gmp-dev openldap-dev curl-dev ldns-dev unbound-dev libsoup3-dev
libxml2-dev tpm2-tss-dev tpm2-tss-sys mariadb-dev wolfssl-dev
libgcrypt-dev botan3-dev pcsc-lite-dev networkmanager-dev
botan3-dev pcsc-lite-dev networkmanager-dev
linux-pam-dev iptables-dev libselinux-dev binutils-dev libunwind-dev
ruby py3-setuptools py3-build py3-tox"
# musl does not provide backtrace(), so use libunwind
-7
View File
@@ -579,13 +579,6 @@ if MONOLITHIC
endif
endif
if USE_GCRYPT
SUBDIRS += plugins/gcrypt
if MONOLITHIC
libstrongswan_la_LIBADD += plugins/gcrypt/libstrongswan-gcrypt.la
endif
endif
if USE_BOTAN
SUBDIRS += plugins/botan
if MONOLITHIC
@@ -69,11 +69,6 @@ static void add_feature_with_ssl(private_curl_plugin_t *this, const char *ssl,
add_feature(this, f);
add_feature(this, PLUGIN_DEPENDS(CUSTOM, "openssl-threading"));
}
else if (strpfx(ssl, "GnuTLS"))
{
add_feature(this, f);
add_feature(this, PLUGIN_DEPENDS(CUSTOM, "gcrypt-threading"));
}
else
{
add_feature(this, f);
@@ -1,23 +0,0 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-gcrypt.la
else
plugin_LTLIBRARIES = libstrongswan-gcrypt.la
endif
libstrongswan_gcrypt_la_SOURCES = \
gcrypt_plugin.h gcrypt_plugin.c \
gcrypt_rsa_public_key.h gcrypt_rsa_public_key.c \
gcrypt_rsa_private_key.h gcrypt_rsa_private_key.c \
gcrypt_dh.h gcrypt_dh.c \
gcrypt_rng.h gcrypt_rng.c \
gcrypt_crypter.h gcrypt_crypter.c \
gcrypt_hasher.h gcrypt_hasher.c
libstrongswan_gcrypt_la_LDFLAGS = -module -avoid-version
libstrongswan_gcrypt_la_LIBADD = -lgcrypt -lgpg-error
@@ -1,333 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "gcrypt_crypter.h"
#include <gcrypt.h>
#include <utils/debug.h>
typedef struct private_gcrypt_crypter_t private_gcrypt_crypter_t;
/**
* Private data of gcrypt_crypter_t
*/
struct private_gcrypt_crypter_t {
/**
* Public part of this class.
*/
gcrypt_crypter_t public;
/**
* gcrypt cipher handle
*/
gcry_cipher_hd_t h;
/**
* gcrypt algorithm identifier
*/
int alg;
/**
* are we using counter mode?
*/
int mode;
/**
* counter state
*/
struct {
char nonce[4];
char iv[8];
uint32_t counter;
} __attribute__((packed)) ctr;
};
/**
* Set the IV for en/decryption
*/
static bool set_iv(private_gcrypt_crypter_t *this, chunk_t iv)
{
if (this->mode == GCRY_CIPHER_MODE_CTR)
{
memcpy(this->ctr.iv, iv.ptr, sizeof(this->ctr.iv));
this->ctr.counter = htonl(1);
return gcry_cipher_setctr(this->h, &this->ctr, sizeof(this->ctr)) == 0;
}
if (iv.len)
{
return gcry_cipher_setiv(this->h, iv.ptr, iv.len) == 0;
}
return TRUE;
}
METHOD(crypter_t, decrypt, bool,
private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
{
if (!set_iv(this, iv))
{
return FALSE;
}
if (dst)
{
*dst = chunk_alloc(data.len);
return gcry_cipher_decrypt(this->h, dst->ptr, dst->len,
data.ptr, data.len) == 0;
}
return gcry_cipher_decrypt(this->h, data.ptr, data.len, NULL, 0) == 0;
}
METHOD(crypter_t, encrypt, bool,
private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
{
if (!set_iv(this, iv))
{
return FALSE;
}
if (dst)
{
*dst = chunk_alloc(data.len);
return gcry_cipher_encrypt(this->h, dst->ptr, dst->len,
data.ptr, data.len) == 0;
}
return gcry_cipher_encrypt(this->h, data.ptr, data.len, NULL, 0) == 0;
}
METHOD(crypter_t, get_block_size, size_t,
private_gcrypt_crypter_t *this)
{
size_t len = 0;
if (this->mode == GCRY_CIPHER_MODE_CTR)
{ /* counter mode does not need any padding */
return 1;
}
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_BLKLEN, NULL, &len);
return len;
}
METHOD(crypter_t, get_iv_size, size_t,
private_gcrypt_crypter_t *this)
{
size_t len = 0;
switch (this->mode)
{
case GCRY_CIPHER_MODE_CTR:
return sizeof(this->ctr.iv);
case GCRY_CIPHER_MODE_ECB:
return 0;
default:
break;
}
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_BLKLEN, NULL, &len);
return len;
}
METHOD(crypter_t, get_key_size, size_t,
private_gcrypt_crypter_t *this)
{
size_t len = 0;
gcry_cipher_algo_info(this->alg, GCRYCTL_GET_KEYLEN, NULL, &len);
if (this->mode == GCRY_CIPHER_MODE_CTR)
{
return len + sizeof(this->ctr.nonce);
}
return len;
}
METHOD(crypter_t, set_key, bool,
private_gcrypt_crypter_t *this, chunk_t key)
{
if (this->mode == GCRY_CIPHER_MODE_CTR)
{
/* last 4 bytes are the nonce */
memcpy(this->ctr.nonce, key.ptr + key.len - sizeof(this->ctr.nonce),
sizeof(this->ctr.nonce));
key.len -= sizeof(this->ctr.nonce);
}
return gcry_cipher_setkey(this->h, key.ptr, key.len) == 0;
}
METHOD(crypter_t, destroy, void,
private_gcrypt_crypter_t *this)
{
gcry_cipher_close(this->h);
free(this);
}
/*
* Described in header
*/
gcrypt_crypter_t *gcrypt_crypter_create(encryption_algorithm_t algo,
size_t key_size)
{
private_gcrypt_crypter_t *this;
int gcrypt_alg;
int mode = GCRY_CIPHER_MODE_CBC;
gcry_error_t err;
switch (algo)
{
case ENCR_DES:
gcrypt_alg = GCRY_CIPHER_DES;
break;
case ENCR_DES_ECB:
gcrypt_alg = GCRY_CIPHER_DES;
mode = GCRY_CIPHER_MODE_ECB;
break;
case ENCR_3DES:
gcrypt_alg = GCRY_CIPHER_3DES;
break;
case ENCR_IDEA:
/* currently not implemented in gcrypt */
return NULL;
case ENCR_CAST:
gcrypt_alg = GCRY_CIPHER_CAST5;
break;
case ENCR_BLOWFISH:
if (key_size != 16 && key_size != 0)
{ /* gcrypt currently supports 128 bit blowfish only */
return NULL;
}
gcrypt_alg = GCRY_CIPHER_BLOWFISH;
break;
case ENCR_AES_CTR:
case ENCR_AES_ECB:
mode = (algo == ENCR_AES_CTR) ? GCRY_CIPHER_MODE_CTR :
GCRY_CIPHER_MODE_ECB;
/* fall */
case ENCR_AES_CBC:
switch (key_size)
{
case 0:
case 16:
gcrypt_alg = GCRY_CIPHER_AES128;
break;
case 24:
gcrypt_alg = GCRY_CIPHER_AES192;
break;
case 32:
gcrypt_alg = GCRY_CIPHER_AES256;
break;
default:
return NULL;
}
break;
case ENCR_AES_CFB:
mode = GCRY_CIPHER_MODE_CFB;
switch (key_size)
{
case 0:
case 16:
gcrypt_alg = GCRY_CIPHER_AES128;
break;
case 24:
gcrypt_alg = GCRY_CIPHER_AES192;
break;
case 32:
gcrypt_alg = GCRY_CIPHER_AES256;
break;
default:
return NULL;
}
break;
case ENCR_CAMELLIA_CTR:
mode = GCRY_CIPHER_MODE_CTR;
/* fall */
case ENCR_CAMELLIA_CBC:
switch (key_size)
{
#ifdef HAVE_GCRY_CIPHER_CAMELLIA
case 0:
case 16:
gcrypt_alg = GCRY_CIPHER_CAMELLIA128;
break;
case 24:
gcrypt_alg = GCRY_CIPHER_CAMELLIA192;
break;
case 32:
gcrypt_alg = GCRY_CIPHER_CAMELLIA256;
break;
#endif /* HAVE_GCRY_CIPHER_CAMELLIA */
default:
return NULL;
}
break;
case ENCR_SERPENT_CBC:
switch (key_size)
{
case 0:
case 16:
gcrypt_alg = GCRY_CIPHER_SERPENT128;
break;
case 24:
gcrypt_alg = GCRY_CIPHER_SERPENT192;
break;
case 32:
gcrypt_alg = GCRY_CIPHER_SERPENT256;
break;
default:
return NULL;
}
break;
case ENCR_TWOFISH_CBC:
switch (key_size)
{
case 0:
case 16:
gcrypt_alg = GCRY_CIPHER_TWOFISH128;
break;
case 32:
gcrypt_alg = GCRY_CIPHER_TWOFISH;
break;
default:
return NULL;
}
break;
default:
return NULL;
}
INIT(this,
.public = {
.crypter = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_block_size = _get_block_size,
.get_iv_size = _get_iv_size,
.get_key_size = _get_key_size,
.set_key = _set_key,
.destroy = _destroy,
},
},
.alg = gcrypt_alg,
.mode = mode,
);
err = gcry_cipher_open(&this->h, gcrypt_alg, mode, 0);
if (err)
{
DBG1(DBG_LIB, "grcy_cipher_open(%N) failed: %s",
encryption_algorithm_names, algo, gpg_strerror(err));
free(this);
return NULL;
}
return &this->public;
}
@@ -1,50 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup gcrypt_crypter gcrypt_crypter
* @{ @ingroup gcrypt_p
*/
#ifndef GCRYPT_CRYPTER_H_
#define GCRYPT_CRYPTER_H_
typedef struct gcrypt_crypter_t gcrypt_crypter_t;
#include <crypto/crypters/crypter.h>
/**
* Implementation of crypters using gcrypt.
*/
struct gcrypt_crypter_t {
/**
* The crypter_t interface.
*/
crypter_t crypter;
};
/**
* Constructor to create gcrypt_crypter_t.
*
* @param algo algorithm to implement
* @param key_size key size in bytes
* @return gcrypt_crypter_t, NULL if not supported
*/
gcrypt_crypter_t *gcrypt_crypter_create(encryption_algorithm_t algo,
size_t key_size);
#endif /** GCRYPT_CRYPTER_H_ @}*/
@@ -1,309 +0,0 @@
/*
* Copyright (C) 2010 Tobias Brunner
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <gcrypt.h>
#include "gcrypt_dh.h"
#include <utils/debug.h>
typedef struct private_gcrypt_dh_t private_gcrypt_dh_t;
/**
* Private data of an gcrypt_dh_t object.
*/
struct private_gcrypt_dh_t {
/**
* Public gcrypt_dh_t interface
*/
gcrypt_dh_t public;
/**
* Diffie Hellman group number
*/
key_exchange_method_t group;
/*
* Generator value
*/
gcry_mpi_t g;
/**
* Own private value
*/
gcry_mpi_t xa;
/**
* Own public value
*/
gcry_mpi_t ya;
/**
* Other public value
*/
gcry_mpi_t yb;
/**
* Shared secret
*/
gcry_mpi_t zz;
/**
* Modulus
*/
gcry_mpi_t p;
/**
* Modulus length.
*/
size_t p_len;
};
METHOD(key_exchange_t, set_public_key, bool,
private_gcrypt_dh_t *this, chunk_t value)
{
gcry_mpi_t p_min_1;
gcry_error_t err;
if (!key_exchange_check_pubkey_len(this->group, value))
{
return FALSE;
}
if (this->yb)
{
gcry_mpi_release(this->yb);
this->yb = NULL;
}
err = gcry_mpi_scan(&this->yb, GCRYMPI_FMT_USG, value.ptr, value.len, NULL);
if (err)
{
DBG1(DBG_LIB, "importing mpi yb failed: %s", gpg_strerror(err));
return FALSE;
}
p_min_1 = gcry_mpi_new(this->p_len * 8);
gcry_mpi_sub_ui(p_min_1, this->p, 1);
/* check that the public value y satisfies 1 < y < p-1.
* according to RFC 6989, section 2.1, this is enough for the common safe-
* prime DH groups (i.e. with q=(p-1)/2 being prime) and also for those
* with small subgroups (22, 23, 24) if private keys are not reused, which
* we never do and explicitly prevent by not resetting this->zz when a
* different public key is set. */
if (gcry_mpi_cmp_ui(this->yb, 1) <= 0 ||
gcry_mpi_cmp(this->yb, p_min_1) >= 0)
{
DBG1(DBG_LIB, "public DH value verification failed: "
"y <= 1 || y >= p - 1");
gcry_mpi_release(p_min_1);
return FALSE;
}
gcry_mpi_release(p_min_1);
return TRUE;
}
/**
* export a gcry_mpi to an allocated chunk of len bytes
*/
static chunk_t export_mpi(gcry_mpi_t value, size_t len)
{
chunk_t chunk;
size_t written;
chunk = chunk_alloc(len);
gcry_mpi_print(GCRYMPI_FMT_USG, chunk.ptr, chunk.len, &written, value);
if (written < len)
{ /* right-align number of written bytes in chunk */
memmove(chunk.ptr + (len - written), chunk.ptr, written);
memset(chunk.ptr, 0, len - written);
}
return chunk;
}
METHOD(key_exchange_t, get_public_key, bool,
private_gcrypt_dh_t *this, chunk_t *value)
{
*value = export_mpi(this->ya, this->p_len);
return TRUE;
}
#ifdef TESTABLE_KE
METHOD(key_exchange_t, set_seed, bool,
private_gcrypt_dh_t *this, chunk_t value, drbg_t *drbg)
{
gcry_error_t err;
gcry_mpi_t xa;
err = gcry_mpi_scan(&xa, GCRYMPI_FMT_USG, value.ptr, value.len, NULL);
if (!err)
{
gcry_mpi_release(this->xa);
this->xa = xa;
gcry_mpi_powm(this->ya, this->g, this->xa, this->p);
gcry_mpi_release(this->zz);
this->zz = NULL;
}
return !err;
}
#endif /* TESTABLE_KE */
METHOD(key_exchange_t, get_shared_secret, bool,
private_gcrypt_dh_t *this, chunk_t *secret)
{
if (!this->zz)
{
this->zz = gcry_mpi_new(this->p_len * 8);
gcry_mpi_powm(this->zz, this->yb, this->xa, this->p);
}
*secret = export_mpi(this->zz, this->p_len);
return TRUE;
}
METHOD(key_exchange_t, get_method, key_exchange_method_t,
private_gcrypt_dh_t *this)
{
return this->group;
}
METHOD(key_exchange_t, destroy, void,
private_gcrypt_dh_t *this)
{
gcry_mpi_release(this->p);
gcry_mpi_release(this->xa);
gcry_mpi_release(this->ya);
gcry_mpi_release(this->g);
gcry_mpi_release(this->yb);
gcry_mpi_release(this->zz);
free(this);
}
/*
* Generic internal constructor
*/
static gcrypt_dh_t *create_generic(key_exchange_method_t group, size_t exp_len,
chunk_t g, chunk_t p)
{
private_gcrypt_dh_t *this;
gcry_error_t err;
chunk_t random;
rng_t *rng;
INIT(this,
.public = {
.ke = {
.get_shared_secret = _get_shared_secret,
.set_public_key = _set_public_key,
.get_public_key = _get_public_key,
.get_method = _get_method,
.destroy = _destroy,
},
},
.group = group,
.p_len = p.len,
);
#ifdef TESTABLE_KE
this->public.ke.set_seed = _set_seed;
#endif
err = gcry_mpi_scan(&this->p, GCRYMPI_FMT_USG, p.ptr, p.len, NULL);
if (err)
{
DBG1(DBG_LIB, "importing mpi modulus failed: %s", gpg_strerror(err));
free(this);
return NULL;
}
err = gcry_mpi_scan(&this->g, GCRYMPI_FMT_USG, g.ptr, g.len, NULL);
if (err)
{
DBG1(DBG_LIB, "importing mpi generator failed: %s", gpg_strerror(err));
gcry_mpi_release(this->p);
free(this);
return NULL;
}
rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
if (rng && rng->allocate_bytes(rng, exp_len, &random))
{ /* prefer external randomizer */
rng->destroy(rng);
err = gcry_mpi_scan(&this->xa, GCRYMPI_FMT_USG,
random.ptr, random.len, NULL);
chunk_clear(&random);
if (err)
{
DBG1(DBG_LIB, "importing mpi xa failed: %s", gpg_strerror(err));
gcry_mpi_release(this->p);
gcry_mpi_release(this->g);
free(this);
return NULL;
}
}
else
{ /* fallback to gcrypt internal randomizer, shouldn't ever happen */
DESTROY_IF(rng);
this->xa = gcry_mpi_new(exp_len * 8);
gcry_mpi_randomize(this->xa, exp_len * 8, GCRY_STRONG_RANDOM);
}
if (exp_len == this->p_len)
{
/* achieve bitsof(p)-1 by setting MSB to 0 */
gcry_mpi_clear_bit(this->xa, exp_len * 8 - 1);
}
this->ya = gcry_mpi_new(this->p_len * 8);
gcry_mpi_powm(this->ya, this->g, this->xa, this->p);
return &this->public;
}
/*
* Described in header.
*/
gcrypt_dh_t *gcrypt_dh_create(key_exchange_method_t group)
{
diffie_hellman_params_t *params;
params = diffie_hellman_get_params(group);
if (!params)
{
return NULL;
}
return create_generic(group, params->exp_len,
params->generator, params->prime);
}
/*
* Described in header.
*/
gcrypt_dh_t *gcrypt_dh_create_custom(key_exchange_method_t group, ...)
{
if (group == MODP_CUSTOM)
{
chunk_t g, p;
VA_ARGS_GET(group, g, p);
return create_generic(group, p.len, g, p);
}
return NULL;
}
@@ -1,58 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup gcrypt_dh gcrypt_dh
* @{ @ingroup gcrypt_p
*/
#ifndef GCRYPT_DH_H_
#define GCRYPT_DH_H_
typedef struct gcrypt_dh_t gcrypt_dh_t;
#include <library.h>
/**
* Implementation of the Diffie-Hellman algorithm using libgcrypt mpi.
*/
struct gcrypt_dh_t {
/**
* Implements key_exchange_t interface.
*/
key_exchange_t ke;
};
/**
* Creates a new gcrypt_dh_t object.
*
* @param group Diffie Hellman group number to use
* @return gcrypt_dh_t object, NULL if not supported
*/
gcrypt_dh_t *gcrypt_dh_create(key_exchange_method_t group);
/**
* Creates a new gcrypt_dh_t object for MODP_CUSTOM.
*
* @param group MODP_CUSTOM
* @param ... expects generator and prime as chunk_t
* @return gcrypt_dh_t object, NULL if not supported
*/
gcrypt_dh_t *gcrypt_dh_create_custom(key_exchange_method_t group, ...);
#endif /** GCRYPT_DH_H_ @}*/
@@ -1,143 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "gcrypt_hasher.h"
#include <utils/debug.h>
#include <gcrypt.h>
typedef struct private_gcrypt_hasher_t private_gcrypt_hasher_t;
/**
* Private data of gcrypt_hasher_t
*/
struct private_gcrypt_hasher_t {
/**
* Public part of this class.
*/
gcrypt_hasher_t public;
/**
* gcrypt hasher context
*/
gcry_md_hd_t hd;
};
METHOD(hasher_t, get_hash_size, size_t,
private_gcrypt_hasher_t *this)
{
return gcry_md_get_algo_dlen(gcry_md_get_algo(this->hd));
}
METHOD(hasher_t, reset, bool,
private_gcrypt_hasher_t *this)
{
gcry_md_reset(this->hd);
return TRUE;
}
METHOD(hasher_t, get_hash, bool,
private_gcrypt_hasher_t *this, chunk_t chunk, uint8_t *hash)
{
gcry_md_write(this->hd, chunk.ptr, chunk.len);
if (hash)
{
memcpy(hash, gcry_md_read(this->hd, 0), get_hash_size(this));
gcry_md_reset(this->hd);
}
return TRUE;
}
METHOD(hasher_t, allocate_hash, bool,
private_gcrypt_hasher_t *this, chunk_t chunk, chunk_t *hash)
{
if (hash)
{
*hash = chunk_alloc(get_hash_size(this));
return get_hash(this, chunk, hash->ptr);
}
return get_hash(this, chunk, NULL);
}
METHOD(hasher_t, destroy, void,
private_gcrypt_hasher_t *this)
{
gcry_md_close(this->hd);
free(this);
}
/*
* Described in header
*/
gcrypt_hasher_t *gcrypt_hasher_create(hash_algorithm_t algo)
{
private_gcrypt_hasher_t *this;
int gcrypt_alg;
gcry_error_t err;
switch (algo)
{
case HASH_MD4:
gcrypt_alg = GCRY_MD_MD4;
break;
case HASH_MD5:
gcrypt_alg = GCRY_MD_MD5;
break;
case HASH_SHA1:
gcrypt_alg = GCRY_MD_SHA1;
break;
case HASH_SHA224:
gcrypt_alg = GCRY_MD_SHA224;
break;
case HASH_SHA256:
gcrypt_alg = GCRY_MD_SHA256;
break;
case HASH_SHA384:
gcrypt_alg = GCRY_MD_SHA384;
break;
case HASH_SHA512:
gcrypt_alg = GCRY_MD_SHA512;
break;
default:
return NULL;
}
INIT(this,
.public = {
.hasher = {
.get_hash = _get_hash,
.allocate_hash = _allocate_hash,
.get_hash_size = _get_hash_size,
.reset = _reset,
.destroy = _destroy,
},
},
);
err = gcry_md_open(&this->hd, gcrypt_alg, 0);
if (err)
{
DBG1(DBG_LIB, "grcy_md_open(%N) failed: %s",
hash_algorithm_names, algo, gpg_strerror(err));
free(this);
return NULL;
}
return &this->public;
}
@@ -1,48 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup gcrypt_hasher gcrypt_hasher
* @{ @ingroup gcrypt_p
*/
#ifndef GCRYPT_HASHER_H_
#define GCRYPT_HASHER_H_
typedef struct gcrypt_hasher_t gcrypt_hasher_t;
#include <crypto/hashers/hasher.h>
/**
* Implementation of hashers using libgcrypt.
*/
struct gcrypt_hasher_t {
/**
* The hasher_t interface.
*/
hasher_t hasher;
};
/**
* Constructor to create gcrypt_hasher_t.
*
* @param algo algorithm
* @return gcrypt_hasher_t, NULL if not supported
*/
gcrypt_hasher_t *gcrypt_hasher_create(hash_algorithm_t algo);
#endif /** GCRYPT_HASHER_H_ @}*/
@@ -1,213 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "gcrypt_plugin.h"
#include "gcrypt_hasher.h"
#include "gcrypt_crypter.h"
#include "gcrypt_rng.h"
#include "gcrypt_dh.h"
#include "gcrypt_rsa_private_key.h"
#include "gcrypt_rsa_public_key.h"
#include <library.h>
#include <utils/debug.h>
#include <threading/mutex.h>
#include <errno.h>
#include <gcrypt.h>
#include <pthread.h>
typedef struct private_gcrypt_plugin_t private_gcrypt_plugin_t;
/**
* private data of gcrypt_plugin
*/
struct private_gcrypt_plugin_t {
/**
* public functions
*/
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)
{
return "gcrypt";
}
METHOD(plugin_t, get_features, int,
private_gcrypt_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
/* we provide threading-safe initialization of libgcrypt */
PLUGIN_PROVIDE(CUSTOM, "gcrypt-threading"),
/* crypters */
PLUGIN_REGISTER(CRYPTER, gcrypt_crypter_create),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 32),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 32),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_ECB, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_ECB, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_ECB, 32),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CFB, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CFB, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CFB, 32),
/* gcrypt only supports 128 bit blowfish */
PLUGIN_PROVIDE(CRYPTER, ENCR_BLOWFISH, 16),
#ifdef HAVE_GCRY_CIPHER_CAMELLIA
PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CTR, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CTR, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CTR, 32),
PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 32),
#endif
PLUGIN_PROVIDE(CRYPTER, ENCR_CAST, 0),
PLUGIN_PROVIDE(CRYPTER, ENCR_3DES, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_DES, 8),
PLUGIN_PROVIDE(CRYPTER, ENCR_DES_ECB, 8),
PLUGIN_PROVIDE(CRYPTER, ENCR_SERPENT_CBC, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_SERPENT_CBC, 24),
PLUGIN_PROVIDE(CRYPTER, ENCR_SERPENT_CBC, 32),
PLUGIN_PROVIDE(CRYPTER, ENCR_TWOFISH_CBC, 16),
PLUGIN_PROVIDE(CRYPTER, ENCR_TWOFISH_CBC, 32),
/* hashers */
PLUGIN_REGISTER(HASHER, gcrypt_hasher_create),
PLUGIN_PROVIDE(HASHER, HASH_MD4),
PLUGIN_PROVIDE(HASHER, HASH_MD5),
PLUGIN_PROVIDE(HASHER, HASH_SHA1),
PLUGIN_PROVIDE(HASHER, HASH_SHA224),
PLUGIN_PROVIDE(HASHER, HASH_SHA256),
PLUGIN_PROVIDE(HASHER, HASH_SHA384),
PLUGIN_PROVIDE(HASHER, HASH_SHA512),
/* MODP DH groups */
PLUGIN_REGISTER(KE, gcrypt_dh_create),
PLUGIN_PROVIDE(KE, MODP_3072_BIT),
PLUGIN_PROVIDE(KE, MODP_4096_BIT),
PLUGIN_PROVIDE(KE, MODP_6144_BIT),
PLUGIN_PROVIDE(KE, MODP_8192_BIT),
PLUGIN_PROVIDE(KE, MODP_2048_BIT),
PLUGIN_PROVIDE(KE, MODP_2048_224),
PLUGIN_PROVIDE(KE, MODP_2048_256),
PLUGIN_PROVIDE(KE, MODP_1536_BIT),
PLUGIN_PROVIDE(KE, MODP_1024_BIT),
PLUGIN_PROVIDE(KE, MODP_1024_160),
PLUGIN_PROVIDE(KE, MODP_768_BIT),
PLUGIN_REGISTER(KE, gcrypt_dh_create_custom),
PLUGIN_PROVIDE(KE, MODP_CUSTOM),
/* RSA private/public key loading */
PLUGIN_REGISTER(PUBKEY, gcrypt_rsa_public_key_load, TRUE),
PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
PLUGIN_REGISTER(PRIVKEY, gcrypt_rsa_private_key_load, TRUE),
PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
PLUGIN_REGISTER(PRIVKEY_GEN, gcrypt_rsa_private_key_gen, FALSE),
PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
/* signature schemes, private */
#if GCRYPT_VERSION_NUMBER >= 0x010700
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS),
#endif
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_NULL),
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_224),
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_256),
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_384),
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_512),
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1),
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_MD5),
PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_PKCS1),
PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_OAEP_SHA1),
/* signature verification schemes */
#if GCRYPT_VERSION_NUMBER >= 0x010700
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS),
#endif
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_224),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_256),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_384),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_512),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_MD5),
PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_PKCS1),
PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA1),
/* random numbers */
PLUGIN_REGISTER(RNG, gcrypt_rng_create),
PLUGIN_PROVIDE(RNG, RNG_WEAK),
PLUGIN_PROVIDE(RNG, RNG_STRONG),
PLUGIN_PROVIDE(RNG, RNG_TRUE),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_gcrypt_plugin_t *this)
{
free(this);
}
/*
* see header file
*/
PLUGIN_DEFINE(gcrypt)
{
private_gcrypt_plugin_t *this;
u_char *dummy[1];
#if GCRYPT_VERSION_NUMBER < 0x010600
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
#endif
if (!gcry_check_version(GCRYPT_VERSION))
{
DBG1(DBG_LIB, "libgcrypt version mismatch");
return NULL;
}
/* we currently do not use secure memory */
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
if (lib->settings->get_bool(lib->settings, "%s.plugins.gcrypt.quick_random",
FALSE, lib->ns))
{
gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
}
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
/* initialize static allocations we want to exclude from leak-detective */
gcry_create_nonce(dummy, sizeof(dummy));
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
return &this->public.plugin;
}
@@ -1,43 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup gcrypt_p gcrypt
* @ingroup plugins
*
* @defgroup gcrypt_plugin gcrypt_plugin
* @{ @ingroup gcrypt_p
*/
#ifndef GCRYPT_PLUGIN_H_
#define GCRYPT_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct gcrypt_plugin_t gcrypt_plugin_t;
/**
* Plugin implementing crypto functions via libgcrypt.
*/
struct gcrypt_plugin_t {
/**
* implements plugin interface
*/
plugin_t plugin;
};
#endif /** GCRYPT_PLUGIN_H_ @}*/
@@ -1,101 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "gcrypt_rng.h"
#include <gcrypt.h>
typedef struct private_gcrypt_rng_t private_gcrypt_rng_t;
/**
* Private data of an gcrypt_rng_t object.
*/
struct private_gcrypt_rng_t {
/**
* Public gcrypt_rng_t interface.
*/
gcrypt_rng_t public;
/**
* RNG quality of this instance
*/
rng_quality_t quality;
};
METHOD(rng_t, get_bytes, bool,
private_gcrypt_rng_t *this, size_t bytes, uint8_t *buffer)
{
switch (this->quality)
{
case RNG_WEAK:
gcry_create_nonce(buffer, bytes);
break;
case RNG_STRONG:
gcry_randomize(buffer, bytes, GCRY_STRONG_RANDOM);
break;
case RNG_TRUE:
gcry_randomize(buffer, bytes, GCRY_VERY_STRONG_RANDOM);
break;
}
return TRUE;
}
METHOD(rng_t, allocate_bytes, bool,
private_gcrypt_rng_t *this, size_t bytes, chunk_t *chunk)
{
*chunk = chunk_alloc(bytes);
get_bytes(this, chunk->len, chunk->ptr);
return TRUE;
}
METHOD(rng_t, destroy, void,
private_gcrypt_rng_t *this)
{
free(this);
}
/*
* Described in header.
*/
gcrypt_rng_t *gcrypt_rng_create(rng_quality_t quality)
{
private_gcrypt_rng_t *this;
switch (quality)
{
case RNG_WEAK:
case RNG_STRONG:
case RNG_TRUE:
break;
default:
return NULL;
}
INIT(this,
.public = {
.rng = {
.get_bytes = _get_bytes,
.allocate_bytes = _allocate_bytes,
.destroy = _destroy,
},
},
.quality = quality,
);
return &this->public;
}
@@ -1,48 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup gcrypt_rng gcrypt_rng
* @{ @ingroup gcrypt_p
*/
#ifndef GCRYPT_RNG_H_
#define GCRYPT_RNG_H_
typedef struct gcrypt_rng_t gcrypt_rng_t;
#include <library.h>
/**
* rng_t implementation using libgcrypt.
*/
struct gcrypt_rng_t {
/**
* Implements rng_t.
*/
rng_t rng;
};
/**
* Creates an gcrypt_rng_t instance.
*
* @param quality required quality of gcryptness
* @return created gcrypt_rng_t
*/
gcrypt_rng_t *gcrypt_rng_create(rng_quality_t quality);
#endif /** GCRYPT_RNG_H_ @} */
@@ -1,751 +0,0 @@
/*
* Copyright (C) 2017 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <gcrypt.h>
#include "gcrypt_rsa_private_key.h"
#include <utils/debug.h>
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <credentials/keys/signature_params.h>
typedef struct private_gcrypt_rsa_private_key_t private_gcrypt_rsa_private_key_t;
/**
* Private data of a gcrypt_rsa_private_key_t object.
*/
struct private_gcrypt_rsa_private_key_t {
/**
* Public interface
*/
gcrypt_rsa_private_key_t public;
/**
* gcrypt S-expression representing an RSA key
*/
gcry_sexp_t key;
/**
* reference count
*/
refcount_t ref;
};
/**
* find a token in a S-expression. If a key is given, its length is used to
* pad the output to a given length.
*/
chunk_t gcrypt_rsa_find_token(gcry_sexp_t sexp, char *name, gcry_sexp_t key)
{
gcry_sexp_t token;
chunk_t data = chunk_empty, tmp;
size_t len = 0;
token = gcry_sexp_find_token(sexp, name, 1);
if (token)
{
data.ptr = (char*)gcry_sexp_nth_data(token, 1, &data.len);
if (!data.ptr)
{
data.len = 0;
}
else
{
if (key)
{
/* gcrypt might return more bytes than necessary. Truncate
* to key length if key given, or prepend zeros if needed */
len = gcry_pk_get_nbits(key);
len = len / 8 + (len % 8 ? 1 : 0);
if (len > data.len)
{
tmp = chunk_alloc(len);
len -= data.len;
memset(tmp.ptr, 0, len);
memcpy(tmp.ptr + len, data.ptr, data.len);
data = tmp;
}
else if (len < data.len)
{
data = chunk_clone(chunk_skip(data, data.len - len));
}
else
{
data = chunk_clone(data);
}
}
else
{
data = chunk_clone(data);
}
}
gcry_sexp_release(token);
}
return data;
}
/**
* Sign a chunk of data with direct PKCS#1 encoding, no hash OID
*/
static bool sign_raw(private_gcrypt_rsa_private_key_t *this,
chunk_t data, chunk_t *signature)
{
gcry_sexp_t in, out;
gcry_error_t err;
chunk_t em;
size_t k;
/* EM = 0x00 || 0x01 || PS || 0x00 || T
* PS = 0xFF padding, with length to fill em
* T = data
*/
k = gcry_pk_get_nbits(this->key) / 8;
if (data.len > k - 3)
{
return FALSE;
}
em = chunk_alloc(k);
memset(em.ptr, 0xFF, em.len);
em.ptr[0] = 0x00;
em.ptr[1] = 0x01;
em.ptr[em.len - data.len - 1] = 0x00;
memcpy(em.ptr + em.len - data.len, data.ptr, data.len);
err = gcry_sexp_build(&in, NULL, "(data(flags raw)(value %b))",
em.len, em.ptr);
chunk_free(&em);
if (err)
{
DBG1(DBG_LIB, "building signature S-expression failed: %s",
gpg_strerror(err));
return FALSE;
}
err = gcry_pk_sign(&out, in, this->key);
gcry_sexp_release(in);
if (err)
{
DBG1(DBG_LIB, "creating pkcs1 signature failed: %s", gpg_strerror(err));
return FALSE;
}
*signature = gcrypt_rsa_find_token(out, "s", this->key);
gcry_sexp_release(out);
return !!signature->len;
}
/**
* Sign a chunk of data using hashing and PKCS#1v1.5/EMSA-PSS encoding
*/
static bool sign_pkcs1(private_gcrypt_rsa_private_key_t *this,
hash_algorithm_t hash_algorithm, rsa_pss_params_t *pss,
chunk_t data, chunk_t *signature)
{
hasher_t *hasher;
chunk_t hash;
gcry_error_t err;
gcry_sexp_t in, out;
char *hash_name = enum_to_name(hash_algorithm_short_names, hash_algorithm);
hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
if (!hasher)
{
DBG1(DBG_LIB, "hash algorithm %N not supported",
hash_algorithm_names, hash_algorithm);
return FALSE;
}
if (!hasher->allocate_hash(hasher, data, &hash))
{
hasher->destroy(hasher);
return FALSE;
}
hasher->destroy(hasher);
if (pss)
{
if (pss->salt.len)
{
err = gcry_sexp_build(&in, NULL,
"(data(flags pss)(salt-length %u)"
"(random-override %b)(hash %s %b))",
pss->salt.len, pss->salt.len, pss->salt.ptr,
hash_name, hash.len, hash.ptr);
}
else
{
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);
}
}
else
{
err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))",
hash_name, hash.len, hash.ptr);
}
chunk_free(&hash);
if (err)
{
DBG1(DBG_LIB, "building signature S-expression failed: %s",
gpg_strerror(err));
return FALSE;
}
err = gcry_pk_sign(&out, in, this->key);
gcry_sexp_release(in);
if (err)
{
DBG1(DBG_LIB, "creating pkcs1 signature failed: %s",
gpg_strerror(err));
return FALSE;
}
*signature = gcrypt_rsa_find_token(out, "s", this->key);
gcry_sexp_release(out);
return !!signature->len;
}
#if GCRYPT_VERSION_NUMBER >= 0x010700
/**
* Sign a chunk of data using hashing and EMSA-PSS encoding
*/
static bool sign_pss(private_gcrypt_rsa_private_key_t *this,
rsa_pss_params_t *params, chunk_t data, chunk_t *signature)
{
if (!params)
{
return FALSE;
}
if (params->mgf1_hash != params->hash)
{
DBG1(DBG_LIB, "unable to use a different MGF1 hash for RSA-PSS");
return FALSE;
}
return sign_pkcs1(this, params->hash, params, data, signature);
}
#endif
METHOD(private_key_t, get_type, key_type_t,
private_gcrypt_rsa_private_key_t *this)
{
return KEY_RSA;
}
METHOD(private_key_t, sign, bool,
private_gcrypt_rsa_private_key_t *this, signature_scheme_t scheme,
void *params, chunk_t data, chunk_t *sig)
{
switch (scheme)
{
case SIGN_RSA_EMSA_PKCS1_NULL:
return sign_raw(this, data, sig);
case SIGN_RSA_EMSA_PKCS1_SHA2_224:
return sign_pkcs1(this, HASH_SHA224, NULL, data, sig);
case SIGN_RSA_EMSA_PKCS1_SHA2_256:
return sign_pkcs1(this, HASH_SHA256, NULL, data, sig);
case SIGN_RSA_EMSA_PKCS1_SHA2_384:
return sign_pkcs1(this, HASH_SHA384, NULL, data, sig);
case SIGN_RSA_EMSA_PKCS1_SHA2_512:
return sign_pkcs1(this, HASH_SHA512, NULL, data, sig);
case SIGN_RSA_EMSA_PKCS1_SHA1:
return sign_pkcs1(this, HASH_SHA1, NULL, data, sig);
case SIGN_RSA_EMSA_PKCS1_MD5:
return sign_pkcs1(this, HASH_MD5, NULL, data, sig);
#if GCRYPT_VERSION_NUMBER >= 0x010700
case SIGN_RSA_EMSA_PSS:
return sign_pss(this, params, data, sig);
#endif
default:
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
signature_scheme_names, scheme);
return FALSE;
}
}
METHOD(private_key_t, decrypt, bool,
private_gcrypt_rsa_private_key_t *this, encryption_scheme_t scheme,
void *params, chunk_t encrypted, chunk_t *plain)
{
gcry_error_t err;
gcry_sexp_t in, out = NULL;
chunk_t label = chunk_empty, decrypted = chunk_empty;
u_char *sexp;
switch (scheme)
{
case ENCRYPT_RSA_PKCS1:
sexp = "(enc-val(flags pkcs1)(rsa(a %b)))";
break;
case ENCRYPT_RSA_OAEP_SHA1:
sexp = "(enc-val(flags oaep)(rsa(a %b)))";
break;
default:
DBG1(DBG_LIB, "encryption scheme %N not supported",
encryption_scheme_names, scheme);
return FALSE;
}
if (scheme == ENCRYPT_RSA_OAEP_SHA1 && params != NULL)
{
label = *(chunk_t *)params;
if (label.len > 0)
{
DBG1(DBG_LIB, "RSA OAEP decryption with a label not supported");
return FALSE;
}
}
err = gcry_sexp_build(&in, NULL, sexp, encrypted.len, encrypted.ptr);
if (err)
{
DBG1(DBG_LIB, "building decryption S-expression failed: %s",
gpg_strerror(err));
return FALSE;
}
err = gcry_pk_decrypt(&out, in, this->key);
gcry_sexp_release(in);
if (err)
{
DBG1(DBG_LIB, "RSA decryption failed: %s", gpg_strerror(err));
return FALSE;
}
decrypted.ptr = (u_char*)gcry_sexp_nth_data(out, 1, &decrypted.len);
*plain = chunk_clone(decrypted);
gcry_sexp_release(out);
return TRUE;
}
METHOD(private_key_t, get_keysize, int,
private_gcrypt_rsa_private_key_t *this)
{
return gcry_pk_get_nbits(this->key);
}
METHOD(private_key_t, get_public_key, public_key_t*,
private_gcrypt_rsa_private_key_t *this)
{
chunk_t n, e;
public_key_t *public;
n = gcrypt_rsa_find_token(this->key, "n", NULL);
e = gcrypt_rsa_find_token(this->key, "e", NULL);
public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
chunk_free(&n);
chunk_free(&e);
return public;
}
METHOD(private_key_t, get_encoding, bool,
private_gcrypt_rsa_private_key_t *this, cred_encoding_type_t type,
chunk_t *encoding)
{
chunk_t cn, ce, cp, cq, cd, cu, cexp1 = chunk_empty, cexp2 = chunk_empty;
gcry_mpi_t p = NULL, q = NULL, d = NULL, exp1, exp2;
gcry_error_t err;
bool success;
/* p and q are swapped, gcrypt expects p < q */
cp = gcrypt_rsa_find_token(this->key, "q", NULL);
cq = gcrypt_rsa_find_token(this->key, "p", NULL);
cd = gcrypt_rsa_find_token(this->key, "d", NULL);
err = gcry_mpi_scan(&p, GCRYMPI_FMT_USG, cp.ptr, cp.len, NULL)
| gcry_mpi_scan(&q, GCRYMPI_FMT_USG, cq.ptr, cq.len, NULL)
| gcry_mpi_scan(&d, GCRYMPI_FMT_USG, cd.ptr, cd.len, NULL);
if (err)
{
gcry_mpi_release(p);
gcry_mpi_release(q);
gcry_mpi_release(d);
chunk_clear(&cp);
chunk_clear(&cq);
chunk_clear(&cd);
DBG1(DBG_LIB, "scanning mpi for export failed: %s", gpg_strerror(err));
return FALSE;
}
gcry_mpi_sub_ui(p, p, 1);
exp1 = gcry_mpi_new(gcry_pk_get_nbits(this->key));
gcry_mpi_mod(exp1, d, p);
gcry_mpi_release(p);
gcry_mpi_sub_ui(q, q, 1);
exp2 = gcry_mpi_new(gcry_pk_get_nbits(this->key));
gcry_mpi_mod(exp2, d, q);
gcry_mpi_release(q);
err = gcry_mpi_aprint(GCRYMPI_FMT_USG, &cexp1.ptr, &cexp1.len, exp1)
| gcry_mpi_aprint(GCRYMPI_FMT_USG, &cexp2.ptr, &cexp2.len, exp2);
gcry_mpi_release(d);
gcry_mpi_release(exp1);
gcry_mpi_release(exp2);
if (err)
{
DBG1(DBG_LIB, "printing mpi for export failed: %s", gpg_strerror(err));
chunk_clear(&cp);
chunk_clear(&cq);
chunk_clear(&cd);
chunk_clear(&cexp1);
chunk_clear(&cexp2);
return FALSE;
}
cn = gcrypt_rsa_find_token(this->key, "n", NULL);
ce = gcrypt_rsa_find_token(this->key, "e", NULL);
cu = gcrypt_rsa_find_token(this->key, "u", NULL);
success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
CRED_PART_RSA_MODULUS, cn,
CRED_PART_RSA_PUB_EXP, ce, CRED_PART_RSA_PRIV_EXP, cd,
CRED_PART_RSA_PRIME1, cp, CRED_PART_RSA_PRIME2, cq,
CRED_PART_RSA_EXP1, cexp1, CRED_PART_RSA_EXP2, cexp2,
CRED_PART_RSA_COEFF, cu, CRED_PART_END);
chunk_free(&cn);
chunk_free(&ce);
chunk_clear(&cd);
chunk_clear(&cp);
chunk_clear(&cq);
chunk_clear(&cexp1);
chunk_clear(&cexp2);
chunk_clear(&cu);
return success;
}
METHOD(private_key_t, get_fingerprint, bool,
private_gcrypt_rsa_private_key_t *this, cred_encoding_type_t type,
chunk_t *fp)
{
chunk_t n, e;
bool success;
if (lib->encoding->get_cache(lib->encoding, type, this, fp))
{
return TRUE;
}
n = gcrypt_rsa_find_token(this->key, "n", NULL);
e = gcrypt_rsa_find_token(this->key, "e", NULL);
success = lib->encoding->encode(lib->encoding,
type, this, fp, CRED_PART_RSA_MODULUS, n,
CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
chunk_free(&n);
chunk_free(&e);
return success;
}
METHOD(private_key_t, get_ref, private_key_t*,
private_gcrypt_rsa_private_key_t *this)
{
ref_get(&this->ref);
return &this->public.key;
}
METHOD(private_key_t, destroy, void,
private_gcrypt_rsa_private_key_t *this)
{
if (ref_put(&this->ref))
{
gcry_sexp_release(this->key);
lib->encoding->clear_cache(lib->encoding, this);
free(this);
}
}
/**
* Internal generic constructor
*/
static private_gcrypt_rsa_private_key_t *create_empty()
{
private_gcrypt_rsa_private_key_t *this;
INIT(this,
.public = {
.key = {
.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;
}
/**
* See header.
*/
gcrypt_rsa_private_key_t *gcrypt_rsa_private_key_gen(key_type_t type,
va_list args)
{
private_gcrypt_rsa_private_key_t *this;
gcry_sexp_t param;
gcry_error_t err;
u_int key_size = 0;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
case BUILD_KEY_SIZE:
key_size = va_arg(args, u_int);
continue;
case BUILD_END:
break;
default:
return NULL;
}
break;
}
if (!key_size)
{
return NULL;
}
err = gcry_sexp_build(&param, NULL, "(genkey(rsa(nbits %d)))", key_size);
if (err)
{
DBG1(DBG_LIB, "building S-expression failed: %s", gpg_strerror(err));
return NULL;
}
this = create_empty();
err = gcry_pk_genkey(&this->key, param);
gcry_sexp_release(param);
if (err)
{
free(this);
DBG1(DBG_LIB, "generating RSA key failed: %s", gpg_strerror(err));
return NULL;
}
return &this->public;
}
/**
* Recover the primes from n, e and d using the algorithm described in
* Appendix C of NIST SP 800-56B.
*/
static bool calculate_pqu(chunk_t cn, chunk_t ce, chunk_t cd, chunk_t *cp,
chunk_t *cq, chunk_t *cu)
{
gcry_mpi_t n, e, d, p, q, u, k, r, g, y, n1, x, two;
int i, t, j;
gcry_error_t err;
bool success = FALSE;
n = e = d = p = q = u = k = r = g = y = n1 = x = two = NULL;
err = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, cn.ptr, cn.len, NULL)
| gcry_mpi_scan(&e, GCRYMPI_FMT_USG, ce.ptr, ce.len, NULL)
| gcry_mpi_scan(&d, GCRYMPI_FMT_USG, cd.ptr, cd.len, NULL);
if (err)
{
goto error;
}
/* k = (d * e) - 1 */
k = gcry_mpi_new(gcry_mpi_get_nbits(n));
gcry_mpi_mul(k, d, e);
gcry_mpi_sub_ui(k, k, 1);
if (gcry_mpi_test_bit(k, 0))
{
goto error;
}
/* k = 2^t * r, where r is the largest odd integer dividing k, and t >= 1 */
r = gcry_mpi_copy(k);
for (t = 0; !gcry_mpi_test_bit(r, 0); t++)
{ /* r = r/2 */
gcry_mpi_rshift(r, r, 1);
}
/* we need n-1 below */
n1 = gcry_mpi_new(gcry_mpi_get_nbits(n));
gcry_mpi_sub_ui(n1, n, 1);
y = gcry_mpi_new(gcry_mpi_get_nbits(n));
g = gcry_mpi_new(gcry_mpi_get_nbits(n));
x = gcry_mpi_new(gcry_mpi_get_nbits(n));
two = gcry_mpi_set_ui(NULL, 2);
for (i = 0; i < 100; i++)
{ /* generate random integer g in [0, n-1] */
do
{
gcry_mpi_randomize(g, gcry_mpi_get_nbits(n), GCRY_WEAK_RANDOM);
}
while (gcry_mpi_cmp(n, g) <= 0);
/* y = g^r mod n */
gcry_mpi_powm(y, g, r, n);
/* try again if y == 1 or y == n-1 */
if (gcry_mpi_cmp_ui(y, 1) == 0 || gcry_mpi_cmp(y, n1) == 0)
{
continue;
}
for (j = 0; j < t; j++)
{ /* x = y^2 mod n */
gcry_mpi_powm(x, y, two, n);
/* stop if x == 1 */
if (gcry_mpi_cmp_ui(x, 1) == 0)
{
goto done;
}
/* retry with new g if x = n-1 */
if (gcry_mpi_cmp(x, n1) == 0)
{
break;
}
/* y = x */
gcry_mpi_set(y, x);
}
}
goto error;
done:
/* p = gcd(y-1, n) */
gcry_mpi_sub_ui(y, y, 1);
p = gcry_mpi_new(gcry_mpi_get_nbits(n));
gcry_mpi_gcd(p, y, n);
/* q = n/p */
q = gcry_mpi_new(gcry_mpi_get_nbits(n));
gcry_mpi_div(q, NULL, n, p, 0);
if (gcry_mpi_cmp(p, q) > 0)
{ /* gcrypt expects q < p */
gcry_mpi_swap(p, q);
}
/* u = q^-1 mod p */
u = gcry_mpi_new(gcry_mpi_get_nbits(n));
gcry_mpi_invm(u, p, q);
err = gcry_mpi_aprint(GCRYMPI_FMT_USG, &cp->ptr, &cp->len, p)
| gcry_mpi_aprint(GCRYMPI_FMT_USG, &cq->ptr, &cq->len, q)
| gcry_mpi_aprint(GCRYMPI_FMT_USG, &cu->ptr, &cu->len, u);
if (err)
{
goto error;
}
success = TRUE;
error:
gcry_mpi_release(n);
gcry_mpi_release(e);
gcry_mpi_release(d);
gcry_mpi_release(p);
gcry_mpi_release(q);
gcry_mpi_release(u);
gcry_mpi_release(k);
gcry_mpi_release(r);
gcry_mpi_release(g);
gcry_mpi_release(y);
gcry_mpi_release(n1);
gcry_mpi_release(x);
gcry_mpi_release(two);
return success;
}
/**
* See header.
*/
gcrypt_rsa_private_key_t *gcrypt_rsa_private_key_load(key_type_t type,
va_list args)
{
private_gcrypt_rsa_private_key_t *this;
chunk_t n, e, d, p, q, u, np, nq, nu;
gcry_error_t err;
n = e = d = p = q = u = np = nq = nu = chunk_empty;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
case BUILD_RSA_MODULUS:
n = va_arg(args, chunk_t);
continue;
case BUILD_RSA_PUB_EXP:
e = va_arg(args, chunk_t);
continue;
case BUILD_RSA_PRIV_EXP:
d = va_arg(args, chunk_t);
continue;
case BUILD_RSA_PRIME1:
/* swap p and q, gcrypt expects p < q */
q = va_arg(args, chunk_t);
continue;
case BUILD_RSA_PRIME2:
p = va_arg(args, chunk_t);
continue;
case BUILD_RSA_EXP1:
case BUILD_RSA_EXP2:
/* not required for gcrypt */
va_arg(args, chunk_t);
continue;
case BUILD_RSA_COEFF:
u = va_arg(args, chunk_t);
continue;
case BUILD_END:
break;
default:
return NULL;
}
break;
}
if (!p.len || !q.len || !u.len)
{
if (!calculate_pqu(n, e, d, &np, &nq, &nu))
{
return NULL;
}
p = np;
q = nq;
u = nu;
}
this = create_empty();
err = gcry_sexp_build(&this->key, NULL,
"(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %b)))",
n.len, n.ptr, e.len, e.ptr, d.len, d.ptr,
p.len, p.ptr, q.len, q.ptr, u.len, u.ptr);
chunk_clear(&np);
chunk_clear(&nq);
chunk_clear(&nu);
if (err)
{
DBG1(DBG_LIB, "loading private key failed: %s", gpg_strerror(err));
free(this);
return NULL;
}
err = gcry_pk_testkey(this->key);
if (err)
{
DBG1(DBG_LIB, "private key sanity check failed: %s", gpg_strerror(err));
destroy(this);
return NULL;
}
return &this->public;
}
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup gcrypt_rsa_private_key gcrypt_rsa_private_key
* @{ @ingroup gcrypt_p
*/
#ifndef GCRYPT_RSA_PRIVATE_KEY_H_
#define GCRYPT_RSA_PRIVATE_KEY_H_
#include <credentials/builder.h>
#include <credentials/keys/private_key.h>
typedef struct gcrypt_rsa_private_key_t gcrypt_rsa_private_key_t;
/**
* Private_key_t implementation of RSA algorithm using libgcrypt.
*/
struct gcrypt_rsa_private_key_t {
/**
* Implements private_key_t interface
*/
private_key_t key;
};
/**
* Generate a private key using gcrypt.
*
* Accepts the BUILD_KEY_SIZE argument.
*
* @param type type of the key, must be KEY_RSA
* @param args builder_part_t argument list
* @return generated key, NULL on failure
*/
gcrypt_rsa_private_key_t *gcrypt_rsa_private_key_gen(key_type_t type,
va_list args);
/**
* Load a gcrypt RSA private keys.
*
* Accepts BUILD_RSA_* components.
*
* @param type type of the key, must be KEY_RSA
* @param args builder_part_t argument list
* @return loaded key, NULL on failure
*/
gcrypt_rsa_private_key_t *gcrypt_rsa_private_key_load(key_type_t type,
va_list args);
#endif /** GCRYPT_RSA_PRIVATE_KEY_H_ @}*/
@@ -1,416 +0,0 @@
/*
* Copyright (C) 2017 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <gcrypt.h>
#include "gcrypt_rsa_public_key.h"
#include <utils/debug.h>
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <crypto/hashers/hasher.h>
#include <credentials/keys/signature_params.h>
typedef struct private_gcrypt_rsa_public_key_t private_gcrypt_rsa_public_key_t;
/**
* Private data structure with signing context.
*/
struct private_gcrypt_rsa_public_key_t {
/**
* Public interface for this signer.
*/
gcrypt_rsa_public_key_t public;
/**
* gcrypt S-expression representing an public RSA key
*/
gcry_sexp_t key;
/**
* reference counter
*/
refcount_t ref;
};
/**
* Implemented in gcrypt_rsa_private_key.c
*/
chunk_t gcrypt_rsa_find_token(gcry_sexp_t sexp, char *name, gcry_sexp_t key);
/**
* verification of a padded PKCS1 signature without an OID
*/
static bool verify_raw(private_gcrypt_rsa_public_key_t *this,
chunk_t data, chunk_t signature)
{
gcry_sexp_t in, sig;
gcry_error_t err;
chunk_t em;
size_t k;
/* EM = 0x00 || 0x01 || PS || 0x00 || T
* PS = 0xFF padding, with length to fill em
* T = data
*/
k = gcry_pk_get_nbits(this->key) / 8;
if (data.len > k - 3)
{
return FALSE;
}
em = chunk_alloc(k);
memset(em.ptr, 0xFF, em.len);
em.ptr[0] = 0x00;
em.ptr[1] = 0x01;
em.ptr[em.len - data.len - 1] = 0x00;
memcpy(em.ptr + em.len - data.len, data.ptr, data.len);
err = gcry_sexp_build(&in, NULL, "(data(flags raw)(value %b))",
em.len, em.ptr);
chunk_free(&em);
if (err)
{
DBG1(DBG_LIB, "building data S-expression failed: %s",
gpg_strerror(err));
return FALSE;
}
err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
signature.len, signature.ptr);
if (err)
{
DBG1(DBG_LIB, "building signature S-expression failed: %s",
gpg_strerror(err));
gcry_sexp_release(in);
return FALSE;
}
err = gcry_pk_verify(sig, in, this->key);
gcry_sexp_release(in);
gcry_sexp_release(sig);
if (err)
{
DBG1(DBG_LIB, "RSA signature verification failed: %s",
gpg_strerror(err));
return FALSE;
}
return TRUE;
}
/**
* Verification of an EMSA PKCS1v1.5 / EMSA-PSS signature described in PKCS#1
*/
static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
hash_algorithm_t algorithm, rsa_pss_params_t *pss,
chunk_t data, chunk_t signature)
{
hasher_t *hasher;
chunk_t hash;
gcry_error_t err;
gcry_sexp_t in, sig;
char *hash_name = enum_to_name(hash_algorithm_short_names, algorithm);
hasher = lib->crypto->create_hasher(lib->crypto, algorithm);
if (!hasher)
{
DBG1(DBG_LIB, "hash algorithm %N not supported",
hash_algorithm_names, algorithm);
return FALSE;
}
if (!hasher->allocate_hash(hasher, data, &hash))
{
hasher->destroy(hasher);
return FALSE;
}
hasher->destroy(hasher);
if (pss)
{
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);
}
else
{
err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))",
hash_name, hash.len, hash.ptr);
}
chunk_free(&hash);
if (err)
{
DBG1(DBG_LIB, "building data S-expression failed: %s",
gpg_strerror(err));
return FALSE;
}
err = gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
signature.len, signature.ptr);
if (err)
{
DBG1(DBG_LIB, "building signature S-expression failed: %s",
gpg_strerror(err));
gcry_sexp_release(in);
return FALSE;
}
err = gcry_pk_verify(sig, in, this->key);
gcry_sexp_release(in);
gcry_sexp_release(sig);
if (err)
{
DBG1(DBG_LIB, "RSA signature verification failed: %s",
gpg_strerror(err));
return FALSE;
}
return TRUE;
}
#if GCRYPT_VERSION_NUMBER >= 0x010700
/**
* Verification of an EMSA-PSS signature described in PKCS#1
*/
static bool verify_pss(private_gcrypt_rsa_public_key_t *this,
rsa_pss_params_t *params, chunk_t data, chunk_t sig)
{
if (!params)
{
return FALSE;
}
if (params->mgf1_hash != params->hash)
{
DBG1(DBG_LIB, "unable to use a different MGF1 hash for RSA-PSS");
return FALSE;
}
return verify_pkcs1(this, params->hash, params, data, sig);
}
#endif
METHOD(public_key_t, get_type, key_type_t,
private_gcrypt_rsa_public_key_t *this)
{
return KEY_RSA;
}
METHOD(public_key_t, verify, bool,
private_gcrypt_rsa_public_key_t *this, signature_scheme_t scheme,
void *params, chunk_t data, chunk_t signature)
{
switch (scheme)
{
case SIGN_RSA_EMSA_PKCS1_NULL:
return verify_raw(this, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA2_224:
return verify_pkcs1(this, HASH_SHA224, NULL, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA2_256:
return verify_pkcs1(this, HASH_SHA256, NULL, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA2_384:
return verify_pkcs1(this, HASH_SHA384, NULL, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA2_512:
return verify_pkcs1(this, HASH_SHA512, NULL, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA1:
return verify_pkcs1(this, HASH_SHA1, NULL, data, signature);
case SIGN_RSA_EMSA_PKCS1_MD5:
return verify_pkcs1(this, HASH_MD5, NULL, data, signature);
#if GCRYPT_VERSION_NUMBER >= 0x010700
case SIGN_RSA_EMSA_PSS:
return verify_pss(this, params, data, signature);
#endif
default:
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
signature_scheme_names, scheme);
return FALSE;
}
}
METHOD(public_key_t, encrypt_, bool,
private_gcrypt_rsa_public_key_t *this, encryption_scheme_t scheme,
void *params, chunk_t plain, chunk_t *encrypted)
{
gcry_error_t err;
gcry_sexp_t in, out = NULL;
chunk_t label = chunk_empty;
u_char *sexp;
switch (scheme)
{
case ENCRYPT_RSA_PKCS1:
sexp = "(data(flags pkcs1)(value %b))";
break;
case ENCRYPT_RSA_OAEP_SHA1:
sexp = "(data(flags oaep)(value %b))";
break;
default:
DBG1(DBG_LIB, "encryption scheme %N not supported",
encryption_scheme_names, scheme);
return FALSE;
}
if (scheme == ENCRYPT_RSA_OAEP_SHA1 && params != NULL)
{
label = *(chunk_t *)params;
if (label.len > 0)
{
DBG1(DBG_LIB, "RSA OAEP encryption with a label not supported");
return FALSE;
}
}
err = gcry_sexp_build(&in, NULL, sexp, plain.len, plain.ptr);
if (err)
{
DBG1(DBG_LIB, "building encryption S-expression failed: %s",
gpg_strerror(err));
return FALSE;
}
err = gcry_pk_encrypt(&out, in, this->key);
gcry_sexp_release(in);
if (err)
{
DBG1(DBG_LIB, "RSA encryption failed: %s", gpg_strerror(err));
return FALSE;
}
*encrypted = gcrypt_rsa_find_token(out, "a", this->key);
gcry_sexp_release(out);
return encrypted->len > 0;
}
METHOD(public_key_t, get_keysize, int,
private_gcrypt_rsa_public_key_t *this)
{
return gcry_pk_get_nbits(this->key);
}
METHOD(public_key_t, get_encoding, bool,
private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
chunk_t *encoding)
{
chunk_t n, e;
bool success;
n = gcrypt_rsa_find_token(this->key, "n", NULL);
e = gcrypt_rsa_find_token(this->key, "e", NULL);
success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e,
CRED_PART_END);
chunk_free(&n);
chunk_free(&e);
return success;
}
METHOD(public_key_t, get_fingerprint, bool,
private_gcrypt_rsa_public_key_t *this, cred_encoding_type_t type,
chunk_t *fp)
{
chunk_t n, e;
bool success;
if (lib->encoding->get_cache(lib->encoding, type, this, fp))
{
return TRUE;
}
n = gcrypt_rsa_find_token(this->key, "n", NULL);
e = gcrypt_rsa_find_token(this->key, "e", NULL);
success = lib->encoding->encode(lib->encoding,
type, this, fp, CRED_PART_RSA_MODULUS, n,
CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
chunk_free(&n);
chunk_free(&e);
return success;
}
METHOD(public_key_t, get_ref, public_key_t*,
private_gcrypt_rsa_public_key_t *this)
{
ref_get(&this->ref);
return &this->public.key;
}
METHOD(public_key_t, destroy, void,
private_gcrypt_rsa_public_key_t *this)
{
if (ref_put(&this->ref))
{
gcry_sexp_release(this->key);
lib->encoding->clear_cache(lib->encoding, this);
free(this);
}
}
/**
* See header.
*/
gcrypt_rsa_public_key_t *gcrypt_rsa_public_key_load(key_type_t type,
va_list args)
{
private_gcrypt_rsa_public_key_t *this;
gcry_error_t err;
chunk_t n, e;
n = e = chunk_empty;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
case BUILD_RSA_MODULUS:
n = va_arg(args, chunk_t);
continue;
case BUILD_RSA_PUB_EXP:
e = va_arg(args, chunk_t);
continue;
case BUILD_END:
break;
default:
return NULL;
}
break;
}
INIT(this,
.public = {
.key = {
.get_type = _get_type,
.verify = _verify,
.encrypt = _encrypt_,
.equals = public_key_equals,
.get_keysize = _get_keysize,
.get_fingerprint = _get_fingerprint,
.has_fingerprint = public_key_has_fingerprint,
.get_encoding = _get_encoding,
.get_ref = _get_ref,
.destroy = _destroy,
},
},
.ref = 1,
);
err = gcry_sexp_build(&this->key, NULL, "(public-key(rsa(n %b)(e %b)))",
n.len, n.ptr, e.len, e.ptr);
if (err)
{
DBG1(DBG_LIB, "loading public key failed: %s", gpg_strerror(err));
free(this);
return NULL;
}
return &this->public;
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2009 Martin Willi
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup gcrypt_rsa_public_key gcrypt_rsa_public_key
* @{ @ingroup gcrypt_p
*/
#ifndef GCRYPT_RSA_PUBLIC_KEY_H_
#define GCRYPT_RSA_PUBLIC_KEY_H_
#include <credentials/builder.h>
#include <credentials/keys/public_key.h>
typedef struct gcrypt_rsa_public_key_t gcrypt_rsa_public_key_t;
/**
* public_key_t implementation of RSA algorithm using libgcrypt.
*/
struct gcrypt_rsa_public_key_t {
/**
* Implements the public_key_t interface
*/
public_key_t key;
};
/**
* Load a RSA public key using gcrypt.
*
* Accepts BUILD_RSA_* components.
*
* @param type type of the key, must be KEY_RSA
* @param args builder_part_t argument list
* @return loaded key, NULL on failure
*/
gcrypt_rsa_public_key_t *gcrypt_rsa_public_key_load(key_type_t type,
va_list args);
#endif /** GCRYPT_RSA_PUBLIC_KEY_H_ @}*/
-3
View File
@@ -336,9 +336,6 @@ static bool pre_test(test_runner_init_t init, char *cfg)
"libstrongswan.plugins.random.random",
lib->settings->get_str(lib->settings,
"libstrongswan.plugins.random.urandom", "/dev/urandom"));
/* same for the gcrypt plugin */
lib->settings->set_default_str(lib->settings,
"libstrongswan.plugins.gcrypt.quick_random", "yes");
if (lib->leak_detective)
{
-6
View File
@@ -564,12 +564,6 @@ static char *whitelist[] = {
/* libldap */
"ldap_int_initialize",
"ldap_pvt_tls_set_option",
/* libgcrypt */
"gcrypt_plugin_create",
"gcry_control",
"gcry_check_version",
"gcry_randomize",
"gcry_create_nonce",
/* OpenSSL: These are needed for unit-tests only, the openssl plugin
* does properly clean up any memory during destroy(). */
"ECDSA_do_sign_ex",
@@ -19,13 +19,4 @@ charon {
}
}
swanctl {
plugins {
# disabled because of entropy issues
gcrypt {
load = no
}
}
}
include strongswan.conf
+1 -1
View File
@@ -48,7 +48,7 @@ esac
SERVICES="apache2 dbus isc-dhcp-server slapd bind9 freeradius"
INC=$INC,${SERVICES// /,}
# packages to install via APT, for SWIMA tests
APT1="libgcrypt20-dev traceroute iptables"
APT1="traceroute iptables"
APT="tmux"
# additional services to disable
case "$BASEIMGSUITE" in
@@ -68,7 +68,6 @@ CONFIG_OPTS = \
--enable-leak-detective \
--enable-load-tester \
--enable-test-vectors \
--enable-gcrypt \
--enable-socket-default \
--enable-socket-dynamic \
--enable-dhcp \
@@ -1,4 +0,0 @@
Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the strong cipher suite
<b>serpent256-sha512-modp4096</b> for the IKE protocol and <b>serpent256-sha512</b>
for ESP packets. A ping from <b>carol</b> to <b>alice</b> successfully checks the
established tunnel.
@@ -1,7 +0,0 @@
carol::ping -c 1 -s 120 -p deadbeef PH_IP_ALICE::128 bytes from PH_IP_ALICE: icmp_.eq=1::YES
carol::swanctl --list-sas --raw 2> /dev/null::home.*version=1 state=ESTABLISHED local-host=192.168.0.100 local-port=500 local-id=carol@strongswan.org remote-host=192.168.0.1 remote-port=500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=SERPENT_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256 prf-alg=PRF_HMAC_SHA2_512 dh-group=MODP_4096.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=SERPENT_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/16]::YES
moon::swanctl --list-sas --raw 2> /dev/null::rw.*version=1 state=ESTABLISHED local-host=192.168.0.1 local-port=500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=500 remote-id=carol@strongswan.org.*encr-alg=SERPENT_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256 prf-alg=PRF_HMAC_SHA2_512 dh-group=MODP_4096.*child-sas.*net.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=SERPENT_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.100/32]::YES
carol::ip xfrm state::enc cbc(serpent)::YES
moon:: ip xfrm state::enc cbc(serpent)::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP.*length 216::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP.*length 216::YES
@@ -1,10 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = nonce pem pkcs1 gcrypt hmac kdf x509 revocation curl vici kernel-netlink socket-default
send_vendor_id = yes
}
@@ -1,26 +0,0 @@
connections {
home {
local_addrs = 192.168.0.100
remote_addrs = 192.168.0.1
local {
auth = pubkey
certs = carolCert.pem
id = carol@strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
home {
remote_ts = 10.1.0.0/16
esp_proposals = serpent256-sha512
}
}
version = 1
proposals = serpent256-sha512-modp4096
}
}
@@ -1,10 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = nonce pem pkcs1 gcrypt hmac kdf x509 revocation vici kernel-netlink socket-default
send_vendor_id = yes
}
@@ -1,24 +0,0 @@
connections {
rw {
local_addrs = 192.168.0.1
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
}
children {
net {
local_ts = 10.1.0.0/16
esp_proposals = serpent256-sha512
}
}
version = 1
proposals = serpent256-sha512-modp4096
}
}
@@ -1,2 +0,0 @@
carol::systemctl stop strongswan
moon::systemctl stop strongswan
@@ -1,5 +0,0 @@
moon::systemctl start strongswan
carol::systemctl start strongswan
moon::expect-connection rw
carol::expect-connection home
carol::swanctl --initiate --child home 2> /dev/null
@@ -1,25 +0,0 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol"
# charon controlled by swanctl
#
SWANCTL=1
@@ -1,4 +0,0 @@
Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the strong cipher suite
<b>twofish256-sha512-modp4096</b> for the IKE protocol and <b>twofish256-sha512</b>
for ESP packets. A ping from <b>carol</b> to <b>alice</b> successfully checks the
established tunnel.
@@ -1,7 +0,0 @@
carol::ping -c 1 -s 120 -p deadbeef PH_IP_ALICE::128 bytes from PH_IP_ALICE: icmp_.eq=1::YES
carol::swanctl --list-sas --raw 2> /dev/null::home.*version=1 state=ESTABLISHED local-host=192.168.0.100 local-port=500 local-id=carol@strongswan.org remote-host=192.168.0.1 remote-port=500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=TWOFISH_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256 prf-alg=PRF_HMAC_SHA2_512 dh-group=MODP_4096.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=TWOFISH_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/16]::YES
moon::swanctl --list-sas --raw 2> /dev/null::rw.*version=1 state=ESTABLISHED local-host=192.168.0.1 local-port=500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=500 remote-id=carol@strongswan.org.*encr-alg=TWOFISH_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256 prf-alg=PRF_HMAC_SHA2_512 dh-group=MODP_4096.*child-sas.*net.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=TWOFISH_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.100/32]::YES
carol::ip xfrm state::enc cbc(twofish)::YES
moon:: ip xfrm state::enc cbc(twofish)::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP.*length 216::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP.*length 216::YES
@@ -1,10 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = nonce pem pkcs1 gcrypt hmac kdf x509 revocation curl vici kernel-netlink socket-default
send_vendor_id = yes
}
@@ -1,26 +0,0 @@
connections {
home {
local_addrs = 192.168.0.100
remote_addrs = 192.168.0.1
local {
auth = pubkey
certs = carolCert.pem
id = carol@strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
home {
remote_ts = 10.1.0.0/16
esp_proposals = twofish256-sha512
}
}
version = 1
proposals = twofish256-sha512-modp4096
}
}
@@ -1,10 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = nonce pem pkcs1 gcrypt hmac kdf x509 revocation vici kernel-netlink socket-default
send_vendor_id = yes
}
@@ -1,24 +0,0 @@
connections {
rw {
local_addrs = 192.168.0.1
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
}
children {
net {
local_ts = 10.1.0.0/16
esp_proposals = twofish256-sha512
}
}
version = 1
proposals = twofish256-sha512-modp4096
}
}
@@ -1,2 +0,0 @@
carol::systemctl stop strongswan
moon::systemctl stop strongswan
@@ -1,5 +0,0 @@
moon::systemctl start strongswan
carol::systemctl start strongswan
moon::expect-connection rw
carol::expect-connection home
carol::swanctl --initiate --child home 2> /dev/null
@@ -1,25 +0,0 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol"
# charon controlled by swanctl
#
SWANCTL=1
@@ -1,3 +0,0 @@
Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the IKE cipher suite
<b>camellia256-sha512-modp3072</b> as well as the ESP cipher suite <b>camellia192-sha384</b>.
A ping from <b>carol</b> to <b>alice</b> successfully checks the established tunnel.
@@ -1,7 +0,0 @@
carol::ping -c 1 -s 120 -p deadbeef PH_IP_ALICE::128 bytes from PH_IP_ALICE: icmp_.eq=1::YES
carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.100 local-port=4500 local-id=carol@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=CAMELLIA_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256 prf-alg=PRF_HMAC_SHA2_512 dh-group=MODP_3072.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=CAMELLIA_CBC encr-keysize=192 integ-alg=HMAC_SHA2_384_192.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/16]::YES
moon:: swanctl --list-sas --raw 2> /dev/null::rw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=4500 remote-id=carol@strongswan.org.*encr-alg=CAMELLIA_CBC encr-keysize=256 integ-alg=HMAC_SHA2_512_256 prf-alg=PRF_HMAC_SHA2_512 dh-group=MODP_3072.*child-sas.*net.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=CAMELLIA_CBC encr-keysize=192 integ-alg=HMAC_SHA2_384_192.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.100/32]::YES
moon:: ip xfrm state::enc cbc(camellia)::YES
carol::ip xfrm state::enc cbc(camellia)::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP.*length 208::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP.*length 208::YES
@@ -1,9 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = random nonce pem pkcs1 gcrypt hmac kdf x509 revocation kernel-netlink curl socket-default updown vici
}
@@ -1,27 +0,0 @@
connections {
home {
local_addrs = 192.168.0.100
remote_addrs = 192.168.0.1
local {
auth = pubkey
certs = carolCert.pem
id = carol@strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
home {
remote_ts = 10.1.0.0/16
updown = /usr/local/libexec/ipsec/_updown iptables
esp_proposals = camellia192-sha384
}
}
version = 2
proposals = camellia256-sha512-modp3072
}
}
@@ -1,9 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = random nonce pem pkcs1 gcrypt hmac kdf x509 revocation kernel-netlink curl socket-default updown vici
}
@@ -1,25 +0,0 @@
connections {
rw {
local_addrs = 192.168.0.1
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
}
children {
net {
local_ts = 10.1.0.0/16
updown = /usr/local/libexec/ipsec/_updown iptables
esp_proposals = camellia192-sha384
}
}
version = 2
proposals = camellia256-sha512-modp3072
}
}
@@ -1,5 +0,0 @@
carol::swanctl --terminate --ike home
carol::systemctl stop strongswan
moon::systemctl stop strongswan
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
@@ -1,7 +0,0 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
moon::systemctl start strongswan
carol::systemctl start strongswan
moon::expect-connection net
carol::expect-connection home
carol::swanctl --initiate --child home 2> /dev/null
@@ -1,25 +0,0 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol"
# charon controlled by swanctl
#
SWANCTL=1
@@ -1,11 +0,0 @@
The roadwarrior <b>carol</b> and the gateway <b>moon</b> use the <b>gcrypt</b>
plugin based on the <b>GNU Libgcrypt</b> library for all cryptographical functions
whereas roadwarrior <b>dave</b> uses <b>openssl</b> as the default <b>strongSwan</b>
cryptographical plugin.
<p>
The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each
to gateway <b>moon</b>. The authentication is based on <b>X.509 certificates</b>.
Upon the successful establishment of the IPsec tunnels, the <b>updown</b> directive
in swanctl.conf automatically inserts iptables-based firewall rules that let pass the
tunneled traffic. In order to test both tunnel and firewall, both <b>carol</b> and
<b>dave</b> ping the client <b>alice</b> behind the gateway <b>moon</b>.
@@ -1,10 +0,0 @@
carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
dave:: ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.100 local-port=4500 local-id=carol@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=3DES_CBC integ-alg=HMAC_SHA1_96 prf-alg=PRF_HMAC_SHA1 dh-group=MODP_1536.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=3DES_CBC integ-alg=HMAC_SHA1_96.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/16]::YES
dave:: swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.200 local-port=4500 local-id=dave@strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*home.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128.*local-ts=\[192.168.0.200/32] remote-ts=\[10.1.0.0/16]::YES
moon:: swanctl --list-sas --ike-id 1 --raw 2> /dev/null::rw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=4500 remote-id=carol@strongswan.org.*encr-alg=3DES_CBC integ-alg=HMAC_SHA1_96 prf-alg=PRF_HMAC_SHA1 dh-group=MODP_1536.*child-sas.*net.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=3DES_CBC integ-alg=HMAC_SHA1_96.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.100/32]::YES
moon:: swanctl --list-sas --ike-id 2 --raw 2> /dev/null::rw.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.200 remote-port=4500 remote-id=dave@strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=MODP_3072.*child-sas.*net.*state=INSTALLED mode=TUNNEL protocol=ESP.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.200/32]::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
@@ -1,13 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = curl test-vectors pem pkcs1 gcrypt nonce x509 revocation hmac kdf xcbc ctr ccm gcm vici kernel-netlink socket-default updown
integrity_test = yes
crypto_test {
on_add = yes
}
}
@@ -1,27 +0,0 @@
connections {
home {
local_addrs = 192.168.0.100
remote_addrs = 192.168.0.1
local {
auth = pubkey
certs = carolCert.pem
id = carol@strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
home {
remote_ts = 10.1.0.0/16
updown = /usr/local/libexec/ipsec/_updown iptables
esp_proposals = 3des-sha1-modp1536
}
}
version = 2
proposals = 3des-sha1-modp1536
}
}
@@ -1,14 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = test-vectors pem pkcs1 random nonce openssl curl revocation xcbc vici stroke kernel-netlink socket-default updown
integrity_test = yes
crypto_test {
required = yes
on_add = yes
}
}
@@ -1,27 +0,0 @@
connections {
home {
local_addrs = 192.168.0.200
remote_addrs = 192.168.0.1
local {
auth = pubkey
certs = daveCert.pem
id = dave@strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
home {
remote_ts = 10.1.0.0/16
updown = /usr/local/libexec/ipsec/_updown iptables
esp_proposals = aes128-sha256-modp3072
}
}
version = 2
proposals = aes128-sha256-modp3072
}
}
@@ -1,13 +0,0 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 pubkey openssl random
}
charon-systemd {
load = curl test-vectors pem pkcs1 gcrypt nonce x509 revocation hmac kdf xcbc ctr ccm gcm vici kernel-netlink socket-default updown
integrity_test = yes
crypto_test {
on_add = yes
}
}
@@ -1,25 +0,0 @@
connections {
rw {
local_addrs = 192.168.0.1
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
}
children {
net {
local_ts = 10.1.0.0/16
updown = /usr/local/libexec/ipsec/_updown iptables
esp_proposals = aes128-sha256-modp3072,3des-sha1-modp1536
}
}
version = 2
proposals = aes128-sha256-modp3072,3des-sha1-modp1536
}
}
@@ -1,8 +0,0 @@
carol::swanctl --terminate --ike home
dave::swanctl --terminate --ike home
carol::systemctl stop strongswan
dave::systemctl stop strongswan
moon::systemctl stop strongswan
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
dave::iptables-restore < /etc/iptables.flush
@@ -1,11 +0,0 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
dave::iptables-restore < /etc/iptables.rules
moon::systemctl start strongswan
carol::systemctl start strongswan
dave::systemctl start strongswan
moon::expect-connection net
carol::expect-connection home
carol::swanctl --initiate --child home 2> /dev/null
dave::expect-connection home
dave::swanctl --initiate --child home 2> /dev/null
@@ -1,25 +0,0 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou dave"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w-d.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol dave"
# charon controlled by swanctl
#
SWANCTL=1